All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/7] Add GTK UI to enable basic accessibility (v3)
@ 2012-09-05 19:18 Anthony Liguori
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 1/7] console: allow VCs to be overridden by UI Anthony Liguori
                   ` (6 more replies)
  0 siblings, 7 replies; 25+ messages in thread
From: Anthony Liguori @ 2012-09-05 19:18 UTC (permalink / raw)
  To: qemu-devel

I realize UIs are the third rail of QEMU development, but over the years I've
gotten a lot of feedback from users about our UI.  I think everyone struggles
with the SDL interface and its lack of discoverability but it's worse than I
think most people realize for users that rely on accessibility tools.

The two pieces of feedback I've gotten the most re: accessibility are the lack
of QEMU's enablement for screen readers and the lack of configurable
accelerators.

Since we render our own terminal using a fixed sized font, we don't respect
system font settings which means we ignore if the user has configured large
print.

We also don't integrate at all with screen readers which means that for blind
users, the virtual consoles may as well not even exist.

We also don't allow any type of configuration of accelerators.  For users with
limited dexterity (this is actually more common than you would think), they may
use an input device that only inputs one key at a time.  Holding down two keys
at once is not possible for these users.

These are solved problems though and while we could reinvent all of this
ourselves with SDL, we would be crazy if we did.  Modern toolkits, like GTK,
solve these problems.

By using GTK, we can leverage VteTerminal for screen reader integration and font
configuration.  We can also use GTK's accelerator support to make accelerators
configurable (Gnome provides a global accelerator configuration interface).

I'm not attempting to make a pretty desktop virtualization UI.  Maybe we'll go
there eventually but that's not what this series is about.

This is just attempting to use a richer toolkit such that we can enable basic
accessibility support.  As a consequence, the UI is much more usable even for a
user without accessibility requirements so it's a win-win.

Also available at:

https://github.com/aliguori/qemu/tree/gtk.5

---
v1 -> v2
 - Add internationalization support.  I don't actually speak any other languages
   so I added a placeholder for a German translation.  This can be tested with
   LANGUAGE=de_DE.UTF-8 qemu-system-x86_64
 - Fixed the terminal size for VteTerminal widgets.  I think the behavior makes
   sense now.
 - Fixed lots of issues raised in review comments (see individual patches)
v2 -> v3
 - Various fixes and rebase
 - An Italian translation from Paolo
 - Significantly refactored resizing since v2

Known Issues:
 - I haven't added backwards compatibility code for older VteTerminal widgets
   yet.  I'm okay with committing this before adding this compatibility as it's
   easy to disable.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [Qemu-devel] [PATCH 1/7] console: allow VCs to be overridden by UI
  2012-09-05 19:18 [Qemu-devel] [PATCH 0/7] Add GTK UI to enable basic accessibility (v3) Anthony Liguori
@ 2012-09-05 19:18 ` Anthony Liguori
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2) Anthony Liguori
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 25+ messages in thread
From: Anthony Liguori @ 2012-09-05 19:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

We want to expose VCs using a VteTerminal widget.  We need access to provide our
own CharDriverState in order to do this.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 console.c   |   14 +++++++++++++-
 console.h   |    6 +++++-
 qemu-char.c |    2 +-
 3 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/console.c b/console.c
index 3b5cabb..88a33f2 100644
--- a/console.c
+++ b/console.c
@@ -1536,7 +1536,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
         chr->init(chr);
 }
 
-CharDriverState *text_console_init(QemuOpts *opts)
+static CharDriverState *text_console_init(QemuOpts *opts)
 {
     CharDriverState *chr;
     TextConsole *s;
@@ -1572,6 +1572,18 @@ CharDriverState *text_console_init(QemuOpts *opts)
     return chr;
 }
 
+static VcHandler *vc_handler = text_console_init;
+
+CharDriverState *vc_init(QemuOpts *opts)
+{
+    return vc_handler(opts);
+}
+
+void register_vc_handler(VcHandler *handler)
+{
+    vc_handler = handler;
+}
+
 void text_consoles_set_display(DisplayState *ds)
 {
     int i;
diff --git a/console.h b/console.h
index 4334db5..eb428f9 100644
--- a/console.h
+++ b/console.h
@@ -359,7 +359,6 @@ void vga_hw_text_update(console_ch_t *chardata);
 
 int is_graphic_console(void);
 int is_fixedsize_console(void);
-CharDriverState *text_console_init(QemuOpts *opts);
 void text_consoles_set_display(DisplayState *ds);
 void console_select(unsigned int index);
 void console_color_init(DisplayState *ds);
@@ -367,6 +366,11 @@ 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);
 
+typedef CharDriverState *(VcHandler)(QemuOpts *);
+
+CharDriverState *vc_init(QemuOpts *opts);
+void register_vc_handler(VcHandler *handler);
+
 /* sdl.c */
 void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
 
diff --git a/qemu-char.c b/qemu-char.c
index 398baf1..18628d2 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2725,7 +2725,7 @@ static const struct {
     { .name = "socket",    .open = qemu_chr_open_socket },
     { .name = "udp",       .open = qemu_chr_open_udp },
     { .name = "msmouse",   .open = qemu_chr_open_msmouse },
-    { .name = "vc",        .open = text_console_init },
+    { .name = "vc",        .open = vc_init },
 #ifdef _WIN32
     { .name = "file",      .open = qemu_chr_open_win_file_out },
     { .name = "pipe",      .open = qemu_chr_open_win_pipe },
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2)
  2012-09-05 19:18 [Qemu-devel] [PATCH 0/7] Add GTK UI to enable basic accessibility (v3) Anthony Liguori
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 1/7] console: allow VCs to be overridden by UI Anthony Liguori
@ 2012-09-05 19:18 ` Anthony Liguori
  2012-09-05 19:53   ` Blue Swirl
                     ` (2 more replies)
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 3/7] gtk: add virtual console support (v2) Anthony Liguori
                   ` (4 subsequent siblings)
  6 siblings, 3 replies; 25+ messages in thread
From: Anthony Liguori @ 2012-09-05 19:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

This is minimalistic and just contains the basic widget infrastructure.  The GUI
consists of a menu and a GtkNotebook.  To start with, the notebook has its tabs
hidden which provides a UI that looks very similar to SDL with the exception of
the menu bar.

The menu bar allows a user to toggle the visibility of the tabs.  Cairo is used
for rendering.

I used gtk-vnc as a reference.  gtk-vnc solves the same basic problems as QEMU
since it was originally written as a remote display for QEMU.  So for the most
part, the approach to rendering and keyboard handling should be pretty solid for
GTK.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
v1 -> v2
 - add gtk-vnc license
 - fix key propagation
---
 Makefile         |    2 +
 configure        |   25 +++-
 console.h        |    4 +
 sysemu.h         |    1 +
 ui/Makefile.objs |    1 +
 ui/gtk.c         |  572 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 604 insertions(+), 1 deletions(-)
 create mode 100644 ui/gtk.c

diff --git a/Makefile b/Makefile
index 1cd5bc8..9523e05 100644
--- a/Makefile
+++ b/Makefile
@@ -122,6 +122,8 @@ ui/cocoa.o: ui/cocoa.m
 
 ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o hw/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
 
+ui/gtk.o: QEMU_CFLAGS += $(GTK_CFLAGS) $(VTE_CFLAGS)
+
 ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 
 bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
diff --git a/configure b/configure
index d97fd81..586dbd3 100755
--- a/configure
+++ b/configure
@@ -278,7 +278,7 @@ sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
 # default flags for all hosts
 QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
 QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
-QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
+QEMU_CFLAGS="-Wredundant-decls $QEMU_CFLAGS"
 QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
 QEMU_INCLUDES="-I. -I\$(SRC_PATH) -I\$(SRC_PATH)/fpu"
 if test "$debug_info" = "yes"; then
@@ -1635,6 +1635,23 @@ if test "$sparse" != "no" ; then
 fi
 
 ##########################################
+# GTK probe
+
+if test "$gtk" != "no"; then
+    if $pkg_config gtk+-2.0 --modversion >/dev/null 2>/dev/null && \
+       $pkg_config vte --modversion >/dev/null 2>/dev/null; then
+	gtk_cflags=`$pkg_config --cflags gtk+-2.0 2>/dev/null`
+	gtk_libs=`$pkg_config --libs gtk+-2.0 2>/dev/null`
+	vte_cflags=`$pkg_config --cflags vte 2>/dev/null`
+	vte_libs=`$pkg_config --libs vte 2>/dev/null`
+	libs_softmmu="$gtk_libs $vte_libs $libs_softmmu"
+	gtk="yes"
+    else
+	gtk="no"
+    fi
+fi
+
+##########################################
 # SDL probe
 
 # Look for sdl configuration program (pkg-config or sdl-config).  Try
@@ -3113,6 +3130,7 @@ if test "$darwin" = "yes" ; then
     echo "Cocoa support     $cocoa"
 fi
 echo "SDL support       $sdl"
+echo "GTK support       $gtk"
 echo "curses support    $curses"
 echo "curl support      $curl"
 echo "mingw32 support   $mingw32"
@@ -3390,6 +3408,11 @@ if test "$bluez" = "yes" ; then
   echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
 fi
 echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
+if test "$gtk" = "yes" ; then
+  echo "CONFIG_GTK=y" >> $config_host_mak
+  echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
+  echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
+fi
 if test "$xen" = "yes" ; then
   echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
   echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
diff --git a/console.h b/console.h
index eb428f9..2bd4814 100644
--- a/console.h
+++ b/console.h
@@ -401,4 +401,8 @@ static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
 /* curses.c */
 void curses_display_init(DisplayState *ds, int full_screen);
 
+/* gtk.c */
+void early_gtk_display_init(void);
+void gtk_display_init(DisplayState *ds);
+
 #endif
diff --git a/sysemu.h b/sysemu.h
index 65552ac..09a8523 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -93,6 +93,7 @@ typedef enum DisplayType
     DT_DEFAULT,
     DT_CURSES,
     DT_SDL,
+    DT_GTK,
     DT_NOGRAPHIC,
     DT_NONE,
 } DisplayType;
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index adc07be..89f8d64 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -12,3 +12,4 @@ common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
 common-obj-$(CONFIG_COCOA) += cocoa.o
 common-obj-$(CONFIG_CURSES) += curses.o
 common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
+common-obj-$(CONFIG_GTK) += gtk.o
diff --git a/ui/gtk.c b/ui/gtk.c
new file mode 100644
index 0000000..e724956
--- /dev/null
+++ b/ui/gtk.c
@@ -0,0 +1,572 @@
+/*
+ * GTK UI
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * Portions from gtk-vnc:
+ *
+ * GTK VNC Widget
+ *
+ * Copyright (C) 2006  Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2009-2010 Daniel P. Berrange <dan@berrange.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <vte/vte.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <pty.h>
+#include <math.h>
+
+#include "qemu-common.h"
+#include "console.h"
+#include "sysemu.h"
+#include "qmp-commands.h"
+#include "x_keymap.h"
+#include "keymaps.h"
+
+//#define DEBUG_GTK
+
+#ifdef DEBUG_GTK
+#define dprintf(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define dprintf(fmt, ...) do { } while (0)
+#endif
+
+typedef struct VirtualConsole
+{
+    GtkWidget *menu_item;
+    GtkWidget *terminal;
+    GtkWidget *scrolled_window;
+    CharDriverState *chr;
+    int fd;
+} VirtualConsole;
+
+typedef struct GtkDisplayState
+{
+    GtkWidget *window;
+
+    GtkWidget *menu_bar;
+
+    GtkWidget *file_menu_item;
+    GtkWidget *file_menu;
+    GtkWidget *quit_item;
+
+    GtkWidget *view_menu_item;
+    GtkWidget *view_menu;
+    GtkWidget *vga_item;
+
+    GtkWidget *show_tabs_item;
+
+    GtkWidget *vbox;
+    GtkWidget *notebook;
+    GtkWidget *drawing_area;
+    cairo_surface_t *surface;
+    DisplayChangeListener dcl;
+    DisplayState *ds;
+    int button_mask;
+    int last_x;
+    int last_y;
+
+    double scale_x;
+    double scale_y;
+
+    GdkCursor *null_cursor;
+    Notifier mouse_mode_notifier;
+} GtkDisplayState;
+
+static GtkDisplayState *global_state;
+
+/** Utility Functions **/
+
+static void gd_update_cursor(GtkDisplayState *s, gboolean override)
+{
+    GdkWindow *window;
+    bool on_vga;
+
+    window = gtk_widget_get_window(GTK_WIDGET(s->drawing_area));
+
+    on_vga = (gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0);
+
+    if ((override || on_vga) && kbd_mouse_is_absolute()) {
+        gdk_window_set_cursor(window, s->null_cursor);
+    } else {
+        gdk_window_set_cursor(window, NULL);
+    }
+}
+
+static void gd_update_caption(GtkDisplayState *s)
+{
+    const char *status = "";
+    gchar *title;
+
+    if (!runstate_is_running()) {
+        status = " [Stopped]";
+    }
+
+    if (qemu_name) {
+        title = g_strdup_printf("QEMU (%s)%s", qemu_name, status);
+    } else {
+        title = g_strdup_printf("QEMU%s", status);
+    }
+        
+    gtk_window_set_title(GTK_WINDOW(s->window), title);
+
+    g_free(title);
+}
+
+/** DisplayState Callbacks **/
+
+static void gd_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    GtkDisplayState *s = ds->opaque;
+    int x1, x2, y1, y2;
+
+    dprintf("update(x=%d, y=%d, w=%d, h=%d)\n", x, y, w, h);
+
+    x1 = floor(x * s->scale_x);
+    y1 = floor(y * s->scale_y);
+
+    x2 = ceil(x * s->scale_x + w * s->scale_x);
+    y2 = ceil(y * s->scale_y + h * s->scale_y);
+
+    gtk_widget_queue_draw_area(s->drawing_area, x1, y1, (x2 - x1), (y2 - y1));
+}
+
+static void gd_refresh(DisplayState *ds)
+{
+    vga_hw_update();
+}
+
+static void gd_resize(DisplayState *ds)
+{
+    GtkDisplayState *s = ds->opaque;
+    cairo_format_t kind;
+    int stride;
+
+    dprintf("resize(width=%d, height=%d)\n",
+            ds->surface->width, ds->surface->height);
+
+    if (s->surface) {
+        cairo_surface_destroy(s->surface);
+    }
+
+    switch (ds->surface->pf.bits_per_pixel) {
+    case 8:
+        kind = CAIRO_FORMAT_A8;
+        break;
+    case 16:
+        kind = CAIRO_FORMAT_RGB16_565;
+        break;
+    case 32:
+        kind = CAIRO_FORMAT_RGB24;
+        break;
+    default:
+        g_assert_not_reached();
+        break;
+    }
+
+    stride = cairo_format_stride_for_width(kind, ds->surface->width);
+    g_assert_cmpint(ds->surface->linesize, ==, stride);
+
+    s->surface = cairo_image_surface_create_for_data(ds->surface->data,
+                                                     kind,
+                                                     ds->surface->width,
+                                                     ds->surface->height,
+                                                     ds->surface->linesize);
+
+    gtk_widget_set_size_request(s->drawing_area,
+                                ds->surface->width * s->scale_x,
+                                ds->surface->height * s->scale_y);
+}
+
+/** QEMU Events **/
+
+static void gd_change_runstate(void *opaque, int running, RunState state)
+{
+    GtkDisplayState *s = opaque;
+
+    gd_update_caption(s);
+}
+
+static void gd_mouse_mode_change(Notifier *notify, void *data)
+{
+    gd_update_cursor(container_of(notify, GtkDisplayState, mouse_mode_notifier),
+                     FALSE);
+}
+
+/** GTK Events **/
+
+static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
+                                void *opaque)
+{
+    if (!no_quit) {
+        qmp_quit(NULL);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+    int ww, wh;
+    int fbw, fbh;
+
+    fbw = s->ds->surface->width;
+    fbh = s->ds->surface->height;
+
+    gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
+
+    cairo_rectangle(cr, 0, 0, ww, wh);
+
+    if (ww != fbw || wh != fbh) {
+        s->scale_x = (double)ww / fbw;
+        s->scale_y = (double)wh / fbh;
+        cairo_scale(cr, s->scale_x, s->scale_y);
+    } else {
+        s->scale_x = 1.0;
+        s->scale_y = 1.0;
+    }
+
+    cairo_set_source_surface(cr, s->surface, 0, 0);
+    cairo_paint(cr);
+
+    return TRUE;
+}
+
+static gboolean gd_expose_event(GtkWidget *widget, GdkEventExpose *expose,
+                                void *opaque)
+{
+    cairo_t *cr;
+    gboolean ret;
+
+    cr = gdk_cairo_create(gtk_widget_get_window(widget));
+    cairo_rectangle(cr,
+                    expose->area.x,
+                    expose->area.y,
+                    expose->area.width,
+                    expose->area.height);
+    cairo_clip(cr);
+
+    ret = gd_draw_event(widget, cr, opaque);
+
+    cairo_destroy(cr);
+
+    return ret;
+}
+
+static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
+                                void *opaque)
+{
+    GtkDisplayState *s = opaque;
+    int dx, dy;
+    int x, y;
+
+    x = motion->x / s->scale_x;
+    y = motion->y / s->scale_y;
+
+    if (kbd_mouse_is_absolute()) {
+        dx = x * 0x7FFF / (s->ds->surface->width - 1);
+        dy = y * 0x7FFF / (s->ds->surface->height - 1);
+    } else if (s->last_x == -1 || s->last_y == -1) {
+        dx = 0;
+        dy = 0;
+    } else {
+        dx = x - s->last_x;
+        dy = y - s->last_y;
+    }
+
+    s->last_x = x;
+    s->last_y = y;
+
+    if (kbd_mouse_is_absolute()) {
+        kbd_mouse_event(dx, dy, 0, s->button_mask);
+    }
+
+    return TRUE;
+}
+
+static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button,
+                                void *opaque)
+{
+    GtkDisplayState *s = opaque;
+    int dx, dy;
+    int n;
+
+    if (button->button == 1) {
+        n = 0x01;
+    } else if (button->button == 2) {
+        n = 0x04;
+    } else if (button->button == 3) {
+        n = 0x02;
+    } else {
+        n = 0x00;
+    }
+
+    if (button->type == GDK_BUTTON_PRESS) {
+        s->button_mask |= n;
+    } else if (button->type == GDK_BUTTON_RELEASE) {
+        s->button_mask &= ~n;
+    }
+
+    if (kbd_mouse_is_absolute()) {
+        dx = s->last_x * 0x7FFF / (s->ds->surface->width - 1);
+        dy = s->last_y * 0x7FFF / (s->ds->surface->height - 1);
+    } else {
+        dx = 0;
+        dy = 0;
+    }
+
+    kbd_mouse_event(dx, dy, 0, s->button_mask);
+        
+    return TRUE;
+}
+
+static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
+{
+    int gdk_keycode;
+    int qemu_keycode;
+
+    gdk_keycode = key->hardware_keycode;
+
+    if (gdk_keycode < 9) {
+        qemu_keycode = 0;
+    } else if (gdk_keycode < 97) {
+        qemu_keycode = gdk_keycode - 8;
+    } else if (gdk_keycode < 158) {
+        qemu_keycode = translate_evdev_keycode(gdk_keycode - 97);
+    } else if (gdk_keycode == 208) { /* Hiragana_Katakana */
+        qemu_keycode = 0x70;
+    } else if (gdk_keycode == 211) { /* backslash */
+        qemu_keycode = 0x73;
+    } else {
+        qemu_keycode = 0;
+    }
+
+    dprintf("translated GDK keycode %d to QEMU keycode %d (%s)\n",
+            gdk_keycode, qemu_keycode,
+            (key->type == GDK_KEY_PRESS) ? "down" : "up");
+
+    if (qemu_keycode & SCANCODE_GREY) {
+        kbd_put_keycode(SCANCODE_EMUL0);
+    }
+
+    if (key->type == GDK_KEY_PRESS) {
+        kbd_put_keycode(qemu_keycode & SCANCODE_KEYCODEMASK);
+    } else if (key->type == GDK_KEY_RELEASE) {
+        kbd_put_keycode(qemu_keycode | SCANCODE_UP);
+    } else {
+        g_assert_not_reached();
+    }
+
+    return TRUE;
+}
+
+/** Window Menu Actions **/
+
+static void gd_menu_quit(GtkMenuItem *item, void *opaque)
+{
+    qmp_quit(NULL);
+}
+
+static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vga_item))) {
+        gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), 0);
+    }
+}
+
+static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->show_tabs_item))) {
+        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), TRUE);
+    } else {
+        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
+    }
+}
+
+static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
+                           gpointer data)
+{
+    GtkDisplayState *s = data;
+
+    if (!gtk_widget_get_realized(s->notebook)) {
+        return;
+    }
+
+    gd_update_cursor(s, TRUE);
+}
+
+void early_gtk_display_init(void)
+{
+}
+
+/** Window Creation **/
+
+static void gd_connect_signals(GtkDisplayState *s)
+{
+    g_signal_connect(s->show_tabs_item, "activate",
+                     G_CALLBACK(gd_menu_show_tabs), s);
+
+    g_signal_connect(s->window, "delete-event",
+                     G_CALLBACK(gd_window_close), s);
+
+    g_signal_connect(s->drawing_area, "expose-event",
+                     G_CALLBACK(gd_expose_event), s);
+    g_signal_connect(s->drawing_area, "motion-notify-event",
+                     G_CALLBACK(gd_motion_event), s);
+    g_signal_connect(s->drawing_area, "button-press-event",
+                     G_CALLBACK(gd_button_event), s);
+    g_signal_connect(s->drawing_area, "button-release-event",
+                     G_CALLBACK(gd_button_event), s);
+    g_signal_connect(s->drawing_area, "key-press-event",
+                     G_CALLBACK(gd_key_event), s);
+    g_signal_connect(s->drawing_area, "key-release-event",
+                     G_CALLBACK(gd_key_event), s);
+
+    g_signal_connect(s->quit_item, "activate",
+                     G_CALLBACK(gd_menu_quit), s);
+    g_signal_connect(s->vga_item, "activate",
+                     G_CALLBACK(gd_menu_switch_vc), s);
+    g_signal_connect(s->notebook, "switch-page",
+                     G_CALLBACK(gd_change_page), s);
+}
+
+static void gd_create_menus(GtkDisplayState *s)
+{
+    GtkStockItem item;
+    GtkAccelGroup *accel_group;
+    GSList *group = NULL;
+    GtkWidget *separator;
+
+    accel_group = gtk_accel_group_new();
+    s->file_menu = gtk_menu_new();
+    gtk_menu_set_accel_group(GTK_MENU(s->file_menu), accel_group);
+    s->file_menu_item = gtk_menu_item_new_with_mnemonic("_File");
+
+    s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
+    gtk_stock_lookup(GTK_STOCK_QUIT, &item);
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item),
+                                 "<QEMU>/File/Quit");
+    gtk_accel_map_add_entry("<QEMU>/File/Quit", item.keyval, item.modifier);
+
+    s->view_menu = gtk_menu_new();
+    gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group);
+    s->view_menu_item = gtk_menu_item_new_with_mnemonic("_View");
+
+    separator = gtk_separator_menu_item_new();
+    gtk_menu_append(GTK_MENU(s->view_menu), separator);
+
+    s->vga_item = gtk_radio_menu_item_new_with_mnemonic(group, "_VGA");
+    group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(s->vga_item));
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->vga_item),
+                                 "<QEMU>/View/VGA");
+    gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+    gtk_menu_append(GTK_MENU(s->view_menu), s->vga_item);
+
+    separator = gtk_separator_menu_item_new();
+    gtk_menu_append(GTK_MENU(s->view_menu), separator);
+
+    s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic("Show _Tabs");
+    gtk_menu_append(GTK_MENU(s->view_menu), s->show_tabs_item);
+
+    g_object_set_data(G_OBJECT(s->window), "accel_group", accel_group);
+    gtk_window_add_accel_group(GTK_WINDOW(s->window), accel_group);
+
+    gtk_menu_append(GTK_MENU(s->file_menu), s->quit_item);
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->file_menu_item), s->file_menu);
+    gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->file_menu_item);
+
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->view_menu_item), s->view_menu);
+    gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->view_menu_item);
+}
+
+void gtk_display_init(DisplayState *ds)
+{
+    GtkDisplayState *s = g_malloc0(sizeof(*s));
+
+    gtk_init(NULL, NULL);
+
+    ds->opaque = s;
+    s->ds = ds;
+    s->dcl.dpy_update = gd_update;
+    s->dcl.dpy_resize = gd_resize;
+    s->dcl.dpy_refresh = gd_refresh;
+    register_displaychangelistener(ds, &s->dcl);
+
+    s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    s->vbox = gtk_vbox_new(FALSE, 0);
+    s->notebook = gtk_notebook_new();
+    s->drawing_area = gtk_drawing_area_new();
+    s->menu_bar = gtk_menu_bar_new();
+
+    s->scale_x = 1.0;
+    s->scale_y = 1.0;
+
+    s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
+
+    s->mouse_mode_notifier.notify = gd_mouse_mode_change;
+    qemu_add_mouse_mode_change_notifier(&s->mouse_mode_notifier);
+    qemu_add_vm_change_state_handler(gd_change_runstate, s);
+
+    gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), s->drawing_area, gtk_label_new("VGA"));
+
+    gd_create_menus(s);
+
+    gd_connect_signals(s);
+
+    gtk_widget_add_events(s->drawing_area,
+                          GDK_POINTER_MOTION_MASK |
+                          GDK_BUTTON_PRESS_MASK |
+                          GDK_BUTTON_RELEASE_MASK |
+                          GDK_BUTTON_MOTION_MASK |
+                          GDK_SCROLL_MASK |
+                          GDK_KEY_PRESS_MASK);
+    gtk_widget_set_double_buffered(s->drawing_area, FALSE);
+    gtk_widget_set_can_focus(s->drawing_area, TRUE);
+
+    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
+    gtk_notebook_set_show_border(GTK_NOTEBOOK(s->notebook), FALSE);
+
+    gtk_window_set_resizable(GTK_WINDOW(s->window), FALSE);
+
+    gd_update_caption(s);
+
+    gtk_box_pack_start(GTK_BOX(s->vbox), s->menu_bar, FALSE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(s->vbox), s->notebook, TRUE, TRUE, 0);
+
+    gtk_container_add(GTK_CONTAINER(s->window), s->vbox);
+
+    gtk_widget_show_all(s->window);
+
+    global_state = s;
+}
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Qemu-devel] [PATCH 3/7] gtk: add virtual console support (v2)
  2012-09-05 19:18 [Qemu-devel] [PATCH 0/7] Add GTK UI to enable basic accessibility (v3) Anthony Liguori
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 1/7] console: allow VCs to be overridden by UI Anthony Liguori
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2) Anthony Liguori
@ 2012-09-05 19:18 ` Anthony Liguori
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 4/7] gtk: add support for input grabbing (v2) Anthony Liguori
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 25+ messages in thread
From: Anthony Liguori @ 2012-09-05 19:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

This enables VteTerminal to be used to render the text consoles.  VteTerminal is
the same widget used by gnome-terminal which means it's VT100 emulation is as
good as they come.

It's also screen reader accessible, supports copy/paste, proper scrolling and
most of the other features you would expect from a terminal widget.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
v1 -> v2
 - make sure to activate the menu item when switching tabs
 - fix sizing of non-0 pages
 - fix build with newer gcc
---
 ui/gtk.c |  159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 159 insertions(+), 0 deletions(-)

diff --git a/ui/gtk.c b/ui/gtk.c
index e724956..0bcb3c2 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -56,6 +56,8 @@
 #define dprintf(fmt, ...) do { } while (0)
 #endif
 
+#define MAX_VCS 10
+
 typedef struct VirtualConsole
 {
     GtkWidget *menu_item;
@@ -79,6 +81,9 @@ typedef struct GtkDisplayState
     GtkWidget *view_menu;
     GtkWidget *vga_item;
 
+    int nb_vcs;
+    VirtualConsole vc[MAX_VCS];
+
     GtkWidget *show_tabs_item;
 
     GtkWidget *vbox;
@@ -400,6 +405,15 @@ static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque)
 
     if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vga_item))) {
         gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), 0);
+    } else {
+        int i;
+
+        for (i = 0; i < s->nb_vcs; i++) {
+            if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vc[i].menu_item))) {
+                gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), i + 1);
+                break;
+            }
+        }
     }
 }
 
@@ -418,16 +432,153 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
                            gpointer data)
 {
     GtkDisplayState *s = data;
+    guint last_page;
 
     if (!gtk_widget_get_realized(s->notebook)) {
         return;
     }
 
+    last_page = gtk_notebook_get_current_page(nb);
+
+    if (last_page) {
+        gtk_widget_set_size_request(s->vc[last_page - 1].terminal, -1, -1);
+    }
+
+    if (arg2 == 0) {
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->vga_item), TRUE);
+    } else {
+        VirtualConsole *vc = &s->vc[arg2 - 1];
+        VteTerminal *term = VTE_TERMINAL(vc->terminal);
+        int width, height;
+
+        width = 80 * vte_terminal_get_char_width(term);
+        height = 25 * vte_terminal_get_char_height(term);
+
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(vc->menu_item), TRUE);
+        gtk_widget_set_size_request(vc->terminal, width, height);
+    }        
+
     gd_update_cursor(s, TRUE);
 }
 
+/** Virtual Console Callbacks **/
+
+static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    VirtualConsole *vc = chr->opaque;
+
+    return write(vc->fd, buf, len);
+}
+
+static int nb_vcs;
+static CharDriverState *vcs[MAX_VCS];
+
+static CharDriverState *gd_vc_handler(QemuOpts *opts)
+{
+    CharDriverState *chr;
+
+    chr = g_malloc0(sizeof(*chr));
+    chr->chr_write = gd_vc_chr_write;
+
+    vcs[nb_vcs++] = chr;
+
+    return chr;
+}
+
 void early_gtk_display_init(void)
 {
+    register_vc_handler(gd_vc_handler);
+}
+
+static gboolean gd_vc_in(GIOChannel *chan, GIOCondition cond, void *opaque)
+{
+    VirtualConsole *vc = opaque;
+    uint8_t buffer[1024];
+    ssize_t len;
+
+    len = read(vc->fd, buffer, sizeof(buffer));
+    if (len <= 0) {
+        return FALSE;
+    }
+
+    qemu_chr_be_write(vc->chr, buffer, len);
+
+    return TRUE;
+}
+
+static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSList *group)
+{
+    const char *label;
+    char buffer[32];
+    char path[32];
+    VtePty *pty;
+    GIOChannel *chan;
+    GtkWidget *scrolled_window;
+    GtkAdjustment *vadjustment;
+    int master_fd, slave_fd, ret;
+    struct termios tty;
+
+    snprintf(buffer, sizeof(buffer), "vc%d", index);
+    snprintf(path, sizeof(path), "<QEMU>/View/VC%d", index);
+
+    vc->chr = vcs[index];
+
+    if (vc->chr->label) {
+        label = vc->chr->label;
+    } else {
+        label = buffer;
+    }
+
+    vc->menu_item = gtk_radio_menu_item_new_with_mnemonic(group, label);
+    group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(vc->menu_item));
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(vc->menu_item), path);
+    gtk_accel_map_add_entry(path, GDK_KEY_2 + index, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+
+    vc->terminal = vte_terminal_new();
+
+    ret = openpty(&master_fd, &slave_fd, NULL, NULL, NULL);
+    g_assert(ret != -1);
+
+    /* Set raw attributes on the pty. */
+    tcgetattr(slave_fd, &tty);
+    cfmakeraw(&tty);
+    tcsetattr(slave_fd, TCSAFLUSH, &tty);
+
+    pty = vte_pty_new_foreign(master_fd, NULL);
+
+    vte_terminal_set_pty_object(VTE_TERMINAL(vc->terminal), pty);
+
+    vte_terminal_set_scrollback_lines(VTE_TERMINAL(vc->terminal), -1);
+
+    vadjustment = vte_terminal_get_adjustment(VTE_TERMINAL(vc->terminal));
+
+    scrolled_window = gtk_scrolled_window_new(NULL, vadjustment);
+    gtk_container_add(GTK_CONTAINER(scrolled_window), vc->terminal);
+
+    vte_terminal_set_size(VTE_TERMINAL(vc->terminal), 80, 25);
+
+    vc->fd = slave_fd;
+    vc->chr->opaque = vc;
+    vc->scrolled_window = scrolled_window;
+
+    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vc->scrolled_window),
+                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+    gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), scrolled_window, gtk_label_new(label));
+    g_signal_connect(vc->menu_item, "activate",
+                     G_CALLBACK(gd_menu_switch_vc), s);
+
+    gtk_menu_append(GTK_MENU(s->view_menu), vc->menu_item);
+
+    qemu_chr_generic_open(vc->chr);
+    if (vc->chr->init) {
+        vc->chr->init(vc->chr);
+    }
+
+    chan = g_io_channel_unix_new(vc->fd);
+    g_io_add_watch(chan, G_IO_IN, gd_vc_in, vc);
+
+    return group;
 }
 
 /** Window Creation **/
@@ -467,6 +618,7 @@ static void gd_create_menus(GtkDisplayState *s)
     GtkAccelGroup *accel_group;
     GSList *group = NULL;
     GtkWidget *separator;
+    int i;
 
     accel_group = gtk_accel_group_new();
     s->file_menu = gtk_menu_new();
@@ -493,6 +645,13 @@ static void gd_create_menus(GtkDisplayState *s)
     gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK);
     gtk_menu_append(GTK_MENU(s->view_menu), s->vga_item);
 
+    for (i = 0; i < nb_vcs; i++) {
+        VirtualConsole *vc = &s->vc[i];
+
+        group = gd_vc_init(s, vc, i, group);
+        s->nb_vcs++;
+    }
+
     separator = gtk_separator_menu_item_new();
     gtk_menu_append(GTK_MENU(s->view_menu), separator);
 
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Qemu-devel] [PATCH 4/7] gtk: add support for input grabbing (v2)
  2012-09-05 19:18 [Qemu-devel] [PATCH 0/7] Add GTK UI to enable basic accessibility (v3) Anthony Liguori
                   ` (2 preceding siblings ...)
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 3/7] gtk: add virtual console support (v2) Anthony Liguori
@ 2012-09-05 19:18 ` Anthony Liguori
  2012-09-05 19:37   ` Jan Kiszka
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 5/7] gtk: add support for screen scaling and full screen (v3) Anthony Liguori
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 25+ messages in thread
From: Anthony Liguori @ 2012-09-05 19:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

There is a small deviation from SDL's behavior here.  Instead of Ctrl+Alt
triggering grab, we now use Ctrl-Alt-g to trigger grab.

GTK will not accept Ctrl+Alt as an accelerator since it just consists of
modifiers.  Having grab as a proper accelerator is important as it allows a user
to override the accelerator for accessibility purposes.

We also are not automatically grabbing on left-click.  Besides the inability to
tie mouse clicks to an accelerator, I think this behavior is hard to discover
and since it only happens depending on the guest state, it can lead to confusing
behavior.

This can be changed in the future if there's a strong resistence to dropping
left-click-to-grab, but I think we're better off dropping it.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
v1 -> v2
 - add a menu option for grab on hover (Jan)
---
 ui/gtk.c |  149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 145 insertions(+), 4 deletions(-)

diff --git a/ui/gtk.c b/ui/gtk.c
index 0bcb3c2..c26f9df 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -79,6 +79,8 @@ typedef struct GtkDisplayState
 
     GtkWidget *view_menu_item;
     GtkWidget *view_menu;
+    GtkWidget *grab_item;
+    GtkWidget *grab_on_hover_item;
     GtkWidget *vga_item;
 
     int nb_vcs;
@@ -107,6 +109,16 @@ static GtkDisplayState *global_state;
 
 /** Utility Functions **/
 
+static bool gd_is_grab_active(GtkDisplayState *s)
+{
+    return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->grab_item));
+}
+
+static bool gd_grab_on_hover(GtkDisplayState *s)
+{
+    return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->grab_on_hover_item));
+}
+
 static void gd_update_cursor(GtkDisplayState *s, gboolean override)
 {
     GdkWindow *window;
@@ -116,7 +128,8 @@ static void gd_update_cursor(GtkDisplayState *s, gboolean override)
 
     on_vga = (gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0);
 
-    if ((override || on_vga) && kbd_mouse_is_absolute()) {
+    if ((override || on_vga) &&
+        (kbd_mouse_is_absolute() || gd_is_grab_active(s))) {
         gdk_window_set_cursor(window, s->null_cursor);
     } else {
         gdk_window_set_cursor(window, NULL);
@@ -127,15 +140,20 @@ static void gd_update_caption(GtkDisplayState *s)
 {
     const char *status = "";
     gchar *title;
+    const char *grab = "";
+
+    if (gd_is_grab_active(s)) {
+        grab = " - Press Ctrl+Alt+G to release grab";
+    }
 
     if (!runstate_is_running()) {
         status = " [Stopped]";
     }
 
     if (qemu_name) {
-        title = g_strdup_printf("QEMU (%s)%s", qemu_name, status);
+        title = g_strdup_printf("QEMU (%s)%s%s", qemu_name, status, grab);
     } else {
-        title = g_strdup_printf("QEMU%s", status);
+        title = g_strdup_printf("QEMU%s%s", status, grab);
     }
         
     gtk_window_set_title(GTK_WINDOW(s->window), title);
@@ -309,10 +327,44 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
     s->last_x = x;
     s->last_y = y;
 
-    if (kbd_mouse_is_absolute()) {
+    if (kbd_mouse_is_absolute() || gd_is_grab_active(s)) {
         kbd_mouse_event(dx, dy, 0, s->button_mask);
     }
 
+    if (!kbd_mouse_is_absolute() && gd_is_grab_active(s)) {
+        GdkDrawable *drawable = GDK_DRAWABLE(gtk_widget_get_window(s->drawing_area));
+        GdkDisplay *display = gdk_drawable_get_display(drawable);
+        GdkScreen *screen = gdk_drawable_get_screen(drawable);
+        int x = (int)motion->x_root;
+        int y = (int)motion->y_root;
+
+        /* In relative mode check to see if client pointer hit
+         * one of the screen edges, and if so move it back by
+         * 200 pixels. This is important because the pointer
+         * in the server doesn't correspond 1-for-1, and so
+         * may still be only half way across the screen. Without
+         * this warp, the server pointer would thus appear to hit
+         * an invisible wall */
+        if (x == 0) {
+            x += 200;
+        }
+        if (y == 0) {
+            y += 200;
+        }
+        if (x == (gdk_screen_get_width(screen) - 1)) {
+            x -= 200;
+        }
+        if (y == (gdk_screen_get_height(screen) - 1)) {
+            y -= 200;
+        }
+
+        if (x != (int)motion->x_root || y != (int)motion->y_root) {
+            gdk_display_warp_pointer(display, screen, x, y);
+            s->last_x = -1;
+            s->last_y = -1;
+            return FALSE;
+        }
+    }        
     return TRUE;
 }
 
@@ -428,11 +480,49 @@ static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque)
     }
 }
 
+static void gd_grab_keyboard(GtkDisplayState *s)
+{
+    gdk_keyboard_grab(gtk_widget_get_window(GTK_WIDGET(s->drawing_area)),
+                      FALSE,
+                      GDK_CURRENT_TIME);
+}
+
+static void gd_ungrab_keyboard(GtkDisplayState *s)
+{
+    gdk_keyboard_ungrab(GDK_CURRENT_TIME);
+}
+
+static void gd_menu_grab_input(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    if (gd_is_grab_active(s)) {
+        gd_grab_keyboard(s);
+        gdk_pointer_grab(gtk_widget_get_window(GTK_WIDGET(s->drawing_area)),
+                         FALSE, /* All events to come to our window directly */
+                         GDK_POINTER_MOTION_MASK |
+                         GDK_BUTTON_PRESS_MASK |
+                         GDK_BUTTON_RELEASE_MASK |
+                         GDK_BUTTON_MOTION_MASK |
+                         GDK_SCROLL_MASK,
+                         NULL, /* Allow cursor to move over entire desktop */
+                         s->null_cursor,
+                         GDK_CURRENT_TIME);
+    } else {
+        gd_ungrab_keyboard(s);
+        gdk_pointer_ungrab(GDK_CURRENT_TIME);
+    }
+
+    gd_update_caption(s);
+    gd_update_cursor(s, FALSE);
+}
+
 static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
                            gpointer data)
 {
     GtkDisplayState *s = data;
     guint last_page;
+    gboolean on_vga;
 
     if (!gtk_widget_get_realized(s->notebook)) {
         return;
@@ -444,6 +534,13 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
         gtk_widget_set_size_request(s->vc[last_page - 1].terminal, -1, -1);
     }
 
+    on_vga = arg2 == 0;
+
+    if (!on_vga) {
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
+                                       FALSE);
+    }
+
     if (arg2 == 0) {
         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->vga_item), TRUE);
     } else {
@@ -458,9 +555,33 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
         gtk_widget_set_size_request(vc->terminal, width, height);
     }        
 
+    gtk_widget_set_sensitive(s->grab_item, on_vga);
+
     gd_update_cursor(s, TRUE);
 }
 
+static gboolean gd_enter_event(GtkWidget *widget, GdkEventCrossing *crossing, gpointer data)
+{
+    GtkDisplayState *s = data;
+
+    if (!gd_is_grab_active(s) && gd_grab_on_hover(s)) {
+        gd_grab_keyboard(s);
+    }
+
+    return TRUE;
+}
+
+static gboolean gd_leave_event(GtkWidget *widget, GdkEventCrossing *crossing, gpointer data)
+{
+    GtkDisplayState *s = data;
+
+    if (!gd_is_grab_active(s) && gd_grab_on_hover(s)) {
+        gd_ungrab_keyboard(s);
+    }
+
+    return TRUE;
+}
+
 /** Virtual Console Callbacks **/
 
 static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
@@ -608,8 +729,14 @@ static void gd_connect_signals(GtkDisplayState *s)
                      G_CALLBACK(gd_menu_quit), s);
     g_signal_connect(s->vga_item, "activate",
                      G_CALLBACK(gd_menu_switch_vc), s);
+    g_signal_connect(s->grab_item, "activate",
+                     G_CALLBACK(gd_menu_grab_input), s);
     g_signal_connect(s->notebook, "switch-page",
                      G_CALLBACK(gd_change_page), s);
+    g_signal_connect(s->drawing_area, "enter-notify-event",
+                     G_CALLBACK(gd_enter_event), s);
+    g_signal_connect(s->drawing_area, "leave-notify-event",
+                     G_CALLBACK(gd_leave_event), s);
 }
 
 static void gd_create_menus(GtkDisplayState *s)
@@ -638,6 +765,18 @@ static void gd_create_menus(GtkDisplayState *s)
     separator = gtk_separator_menu_item_new();
     gtk_menu_append(GTK_MENU(s->view_menu), separator);
 
+    s->grab_on_hover_item = gtk_check_menu_item_new_with_mnemonic("Grab On _Hover");
+    gtk_menu_append(GTK_MENU(s->view_menu), s->grab_on_hover_item);
+
+    s->grab_item = gtk_check_menu_item_new_with_mnemonic("_Grab Input");
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->grab_item),
+                                 "<QEMU>/View/Grab Input");
+    gtk_accel_map_add_entry("<QEMU>/View/Grab Input", GDK_KEY_g, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+    gtk_menu_append(GTK_MENU(s->view_menu), s->grab_item);
+
+    separator = gtk_separator_menu_item_new();
+    gtk_menu_append(GTK_MENU(s->view_menu), separator);
+
     s->vga_item = gtk_radio_menu_item_new_with_mnemonic(group, "_VGA");
     group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(s->vga_item));
     gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->vga_item),
@@ -708,6 +847,8 @@ void gtk_display_init(DisplayState *ds)
                           GDK_BUTTON_PRESS_MASK |
                           GDK_BUTTON_RELEASE_MASK |
                           GDK_BUTTON_MOTION_MASK |
+                          GDK_ENTER_NOTIFY_MASK |
+                          GDK_LEAVE_NOTIFY_MASK |
                           GDK_SCROLL_MASK |
                           GDK_KEY_PRESS_MASK);
     gtk_widget_set_double_buffered(s->drawing_area, FALSE);
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Qemu-devel] [PATCH 5/7] gtk: add support for screen scaling and full screen (v3)
  2012-09-05 19:18 [Qemu-devel] [PATCH 0/7] Add GTK UI to enable basic accessibility (v3) Anthony Liguori
                   ` (3 preceding siblings ...)
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 4/7] gtk: add support for input grabbing (v2) Anthony Liguori
@ 2012-09-05 19:18 ` Anthony Liguori
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 6/7] gtk: add translation support Anthony Liguori
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 7/7] gtk: make default UI (v3) Anthony Liguori
  6 siblings, 0 replies; 25+ messages in thread
From: Anthony Liguori @ 2012-09-05 19:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

Basic menu items to enter full screen mode and zoom in/out.  Unlike SDL, we
don't allow arbitrary scaling based on window resizing.  The current behavior
with SDL causes a lot of problems for me.

Sometimes I accidentally resize the window a tiny bit while trying to move it
(Ubuntu's 1-pixel window decorations don't help here).  After that, scaling is
now active and if the screen changes size again, badness ensues since the
aspect ratio is skewed.

Allowing zooming by 25% in and out should cover most use cases.  We can add a
more flexible scaling later but for now, I think this is a more friendly
behavior.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
v1 -> v2
 - fix scaling (Paolo)
 - use ctrl-alt-+ instead of ctrl-alt-= for zoom
v2 -> v3
 - add a zoom to 100% menu (Stefan)
 - allow window to be resizable
---
 ui/gtk.c |  253 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 236 insertions(+), 17 deletions(-)

diff --git a/ui/gtk.c b/ui/gtk.c
index c26f9df..5a5d8e2 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -79,6 +79,11 @@ typedef struct GtkDisplayState
 
     GtkWidget *view_menu_item;
     GtkWidget *view_menu;
+    GtkWidget *full_screen_item;
+    GtkWidget *zoom_in_item;
+    GtkWidget *zoom_out_item;
+    GtkWidget *zoom_fixed_item;
+    GtkWidget *zoom_fit_item;
     GtkWidget *grab_item;
     GtkWidget *grab_on_hover_item;
     GtkWidget *vga_item;
@@ -100,9 +105,11 @@ typedef struct GtkDisplayState
 
     double scale_x;
     double scale_y;
+    gboolean full_screen;
 
     GdkCursor *null_cursor;
     Notifier mouse_mode_notifier;
+    gboolean free_scale;
 } GtkDisplayState;
 
 static GtkDisplayState *global_state;
@@ -129,7 +136,7 @@ static void gd_update_cursor(GtkDisplayState *s, gboolean override)
     on_vga = (gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0);
 
     if ((override || on_vga) &&
-        (kbd_mouse_is_absolute() || gd_is_grab_active(s))) {
+        (s->full_screen || kbd_mouse_is_absolute() || gd_is_grab_active(s))) {
         gdk_window_set_cursor(window, s->null_cursor);
     } else {
         gdk_window_set_cursor(window, NULL);
@@ -167,6 +174,9 @@ static void gd_update(DisplayState *ds, int x, int y, int w, int h)
 {
     GtkDisplayState *s = ds->opaque;
     int x1, x2, y1, y2;
+    int mx, my;
+    int fbw, fbh;
+    int ww, wh;
 
     dprintf("update(x=%d, y=%d, w=%d, h=%d)\n", x, y, w, h);
 
@@ -176,7 +186,20 @@ static void gd_update(DisplayState *ds, int x, int y, int w, int h)
     x2 = ceil(x * s->scale_x + w * s->scale_x);
     y2 = ceil(y * s->scale_y + h * s->scale_y);
 
-    gtk_widget_queue_draw_area(s->drawing_area, x1, y1, (x2 - x1), (y2 - y1));
+    fbw = s->ds->surface->width * s->scale_x;
+    fbh = s->ds->surface->height * s->scale_y;
+
+    gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh);
+
+    mx = my = 0;
+    if (ww > fbw) {
+        mx = (ww - fbw) / 2;
+    }
+    if (wh > fbh) {
+        my = (wh - fbh) / 2;
+    }
+
+    gtk_widget_queue_draw_area(s->drawing_area, mx + x1, my + y1, (x2 - x1), (y2 - y1));
 }
 
 static void gd_refresh(DisplayState *ds)
@@ -221,9 +244,28 @@ static void gd_resize(DisplayState *ds)
                                                      ds->surface->height,
                                                      ds->surface->linesize);
 
-    gtk_widget_set_size_request(s->drawing_area,
-                                ds->surface->width * s->scale_x,
-                                ds->surface->height * s->scale_y);
+    if (!s->full_screen) {
+        GtkRequisition req;
+        double sx, sy;
+
+        if (s->free_scale) {
+            sx = s->scale_x;
+            sy = s->scale_y;
+
+            s->scale_y = 1.0;
+            s->scale_x = 1.0;
+        } else {
+            sx = 1.0;
+            sy = 1.0;
+        }
+
+        gtk_widget_set_size_request(s->drawing_area,
+                                    ds->surface->width * s->scale_x,
+                                    ds->surface->height * s->scale_y);
+        gtk_widget_size_request(s->vbox, &req);
+
+        gtk_window_resize(GTK_WINDOW(s->window), req.width * sx, req.height * sy);
+    }
 }
 
 /** QEMU Events **/
@@ -257,26 +299,55 @@ static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
 static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
 {
     GtkDisplayState *s = opaque;
+    int mx, my;
     int ww, wh;
     int fbw, fbh;
 
+    if (!gtk_widget_get_realized(widget)) {
+        return FALSE;
+    }
+
     fbw = s->ds->surface->width;
     fbh = s->ds->surface->height;
 
     gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
 
-    cairo_rectangle(cr, 0, 0, ww, wh);
-
-    if (ww != fbw || wh != fbh) {
+    if (s->full_screen) {
         s->scale_x = (double)ww / fbw;
         s->scale_y = (double)wh / fbh;
-        cairo_scale(cr, s->scale_x, s->scale_y);
-    } else {
-        s->scale_x = 1.0;
-        s->scale_y = 1.0;
+    } else if (s->free_scale) {
+        double sx, sy;
+
+        sx = (double)ww / fbw;
+        sy = (double)wh / fbh;
+
+        s->scale_x = s->scale_y = MIN(sx, sy);
+    }
+
+    fbw *= s->scale_x;
+    fbh *= s->scale_y;
+
+    mx = my = 0;
+    if (ww > fbw) {
+        mx = (ww - fbw) / 2;
+    }
+    if (wh > fbh) {
+        my = (wh - fbh) / 2;
     }
 
-    cairo_set_source_surface(cr, s->surface, 0, 0);
+    cairo_rectangle(cr, 0, 0, ww, wh);
+
+    /* Optionally cut out the inner area where the pixmap
+       will be drawn. This avoids 'flashing' since we're
+       not double-buffering. Note we're using the undocumented
+       behaviour of drawing the rectangle from right to left
+       to cut out the whole */
+    cairo_rectangle(cr, mx + fbw, my,
+                    -1 * fbw, fbh);
+    cairo_fill(cr);
+
+    cairo_scale(cr, s->scale_x, s->scale_y);
+    cairo_set_source_surface(cr, s->surface, mx / s->scale_x, my / s->scale_y);
     cairo_paint(cr);
 
     return TRUE;
@@ -309,9 +380,31 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
     GtkDisplayState *s = opaque;
     int dx, dy;
     int x, y;
+    int mx, my;
+    int fbh, fbw;
+    int ww, wh;
+
+    fbw = s->ds->surface->width * s->scale_x;
+    fbh = s->ds->surface->height * s->scale_y;
+
+    gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh);
+
+    mx = my = 0;
+    if (ww > fbw) {
+        mx = (ww - fbw) / 2;
+    }
+    if (wh > fbh) {
+        my = (wh - fbh) / 2;
+    }
+
+    x = (motion->x - mx) / s->scale_x;
+    y = (motion->y - my) / s->scale_y;
 
-    x = motion->x / s->scale_x;
-    y = motion->y / s->scale_y;
+    if (x < 0 || y < 0 ||
+        x >= s->ds->surface->width ||
+        y >= s->ds->surface->height) {
+        return TRUE;
+    }
 
     if (kbd_mouse_is_absolute()) {
         dx = x * 0x7FFF / (s->ds->surface->width - 1);
@@ -480,6 +573,90 @@ static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque)
     }
 }
 
+static void gd_menu_full_screen(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->full_screen_item))) {
+        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
+        gtk_widget_set_size_request(s->menu_bar, 0, 0);
+        gtk_widget_set_size_request(s->drawing_area, -1, -1);
+        gtk_window_fullscreen(GTK_WINDOW(s->window));
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), TRUE);
+        s->full_screen = TRUE;
+    } else {
+        gtk_window_unfullscreen(GTK_WINDOW(s->window));
+        gd_menu_show_tabs(GTK_MENU_ITEM(s->show_tabs_item), s);
+        gtk_widget_set_size_request(s->menu_bar, -1, -1);
+        gtk_widget_set_size_request(s->drawing_area, s->ds->surface->width, s->ds->surface->height);
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), FALSE);
+        s->full_screen = FALSE;
+        s->scale_x = 1.0;
+        s->scale_y = 1.0;
+    }
+
+    gd_update_cursor(s, FALSE);
+}
+
+static void gd_menu_zoom_in(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item),
+                                   FALSE);
+
+    s->scale_x += .25;
+    s->scale_y += .25;
+
+    gd_resize(s->ds);
+}
+
+static void gd_menu_zoom_out(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item),
+                                   FALSE);
+
+    s->scale_x -= .25;
+    s->scale_y -= .25;
+
+    s->scale_x = MAX(s->scale_x, .25);
+    s->scale_y = MAX(s->scale_y, .25);
+
+    gd_resize(s->ds);
+}
+
+static void gd_menu_zoom_fixed(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    s->scale_x = 1.0;
+    s->scale_y = 1.0;
+
+    gd_resize(s->ds);
+}
+
+static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+    int ww, wh;
+
+    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item))) {
+        s->free_scale = TRUE;
+    } else {
+        s->free_scale = FALSE;
+    }
+
+    s->scale_x = 1.0;
+    s->scale_y = 1.0;
+
+    gd_resize(s->ds);
+
+    gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh);
+    gtk_widget_queue_draw_area(s->drawing_area, 0, 0, ww, wh);
+}
+
 static void gd_grab_keyboard(GtkDisplayState *s)
 {
     gdk_keyboard_grab(gtk_widget_get_window(GTK_WIDGET(s->drawing_area)),
@@ -539,6 +716,9 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
     if (!on_vga) {
         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
                                        FALSE);
+    } else if (s->full_screen) {
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
+                                       TRUE);
     }
 
     if (arg2 == 0) {
@@ -727,6 +907,16 @@ static void gd_connect_signals(GtkDisplayState *s)
 
     g_signal_connect(s->quit_item, "activate",
                      G_CALLBACK(gd_menu_quit), s);
+    g_signal_connect(s->full_screen_item, "activate",
+                     G_CALLBACK(gd_menu_full_screen), s);
+    g_signal_connect(s->zoom_in_item, "activate",
+                     G_CALLBACK(gd_menu_zoom_in), s);
+    g_signal_connect(s->zoom_out_item, "activate",
+                     G_CALLBACK(gd_menu_zoom_out), s);
+    g_signal_connect(s->zoom_fixed_item, "activate",
+                     G_CALLBACK(gd_menu_zoom_fixed), s);
+    g_signal_connect(s->zoom_fit_item, "activate",
+                     G_CALLBACK(gd_menu_zoom_fit), s);
     g_signal_connect(s->vga_item, "activate",
                      G_CALLBACK(gd_menu_switch_vc), s);
     g_signal_connect(s->grab_item, "activate",
@@ -762,6 +952,36 @@ static void gd_create_menus(GtkDisplayState *s)
     gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group);
     s->view_menu_item = gtk_menu_item_new_with_mnemonic("_View");
 
+    s->full_screen_item = gtk_check_menu_item_new_with_mnemonic("_Full Screen");
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->full_screen_item),
+                                 "<QEMU>/View/Full Screen");
+    gtk_accel_map_add_entry("<QEMU>/View/Full Screen", GDK_KEY_f, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+    gtk_menu_append(GTK_MENU(s->view_menu), s->full_screen_item);
+
+    separator = gtk_separator_menu_item_new();
+    gtk_menu_append(GTK_MENU(s->view_menu), separator);
+
+    s->zoom_in_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_IN, NULL);
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_in_item),
+                                 "<QEMU>/View/Zoom In");
+    gtk_accel_map_add_entry("<QEMU>/View/Zoom In", GDK_KEY_plus, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+    gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_in_item);
+
+    s->zoom_out_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_OUT, NULL);
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_out_item),
+                                 "<QEMU>/View/Zoom Out");
+    gtk_accel_map_add_entry("<QEMU>/View/Zoom Out", GDK_KEY_minus, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+    gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_out_item);
+
+    s->zoom_fixed_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_100, NULL);
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_fixed_item),
+                                 "<QEMU>/View/Zoom Fixed");
+    gtk_accel_map_add_entry("<QEMU>/View/Zoom Fixed", GDK_KEY_0, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+    gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fixed_item);
+
+    s->zoom_fit_item = gtk_check_menu_item_new_with_mnemonic(_("Zoom To _Fit"));
+    gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fit_item);
+
     separator = gtk_separator_menu_item_new();
     gtk_menu_append(GTK_MENU(s->view_menu), separator);
 
@@ -829,6 +1049,7 @@ void gtk_display_init(DisplayState *ds)
 
     s->scale_x = 1.0;
     s->scale_y = 1.0;
+    s->free_scale = FALSE;
 
     s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
 
@@ -857,8 +1078,6 @@ void gtk_display_init(DisplayState *ds)
     gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
     gtk_notebook_set_show_border(GTK_NOTEBOOK(s->notebook), FALSE);
 
-    gtk_window_set_resizable(GTK_WINDOW(s->window), FALSE);
-
     gd_update_caption(s);
 
     gtk_box_pack_start(GTK_BOX(s->vbox), s->menu_bar, FALSE, TRUE, 0);
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Qemu-devel] [PATCH 6/7] gtk: add translation support
  2012-09-05 19:18 [Qemu-devel] [PATCH 0/7] Add GTK UI to enable basic accessibility (v3) Anthony Liguori
                   ` (4 preceding siblings ...)
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 5/7] gtk: add support for screen scaling and full screen (v3) Anthony Liguori
@ 2012-09-05 19:18 ` Anthony Liguori
  2012-09-06 12:18   ` Kevin Wolf
  2012-09-06 13:00   ` Peter Maydell
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 7/7] gtk: make default UI (v3) Anthony Liguori
  6 siblings, 2 replies; 25+ messages in thread
From: Anthony Liguori @ 2012-09-05 19:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

This includes a de_DE translation from Kevin Wolf and an it translation from
Paolo Bonzini.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 Makefile       |    3 +++
 configure      |    4 +++-
 po/Makefile    |   43 +++++++++++++++++++++++++++++++++++++++++++
 po/de_DE.po    |   37 +++++++++++++++++++++++++++++++++++++
 po/it.po       |   37 +++++++++++++++++++++++++++++++++++++
 po/messages.po |   37 +++++++++++++++++++++++++++++++++++++
 ui/gtk.c       |   20 ++++++++++++++------
 7 files changed, 174 insertions(+), 7 deletions(-)
 create mode 100644 po/Makefile
 create mode 100644 po/de_DE.po
 create mode 100644 po/it.po
 create mode 100644 po/messages.po

diff --git a/Makefile b/Makefile
index 9523e05..d75ef30 100644
--- a/Makefile
+++ b/Makefile
@@ -315,6 +315,9 @@ ifneq ($(BLOBS),)
 		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
 	done
 endif
+ifeq ($(CONFIG_GTK),y)
+	$(MAKE) -C po $@ || exit 1
+endif
 	$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps"
 	set -e; for x in $(KEYMAPS); do \
 		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
diff --git a/configure b/configure
index 586dbd3..befc65c 100755
--- a/configure
+++ b/configure
@@ -3055,6 +3055,7 @@ fi
 
 qemu_confdir=$sysconfdir$confsuffix
 qemu_datadir=$datadir$confsuffix
+qemu_localedir="$datadir/locale"
 
 tools=
 if test "$softmmu" = yes ; then
@@ -3207,6 +3208,7 @@ echo "sysconfdir=$sysconfdir" >> $config_host_mak
 echo "qemu_confdir=$qemu_confdir" >> $config_host_mak
 echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
 echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
+echo "qemu_localedir=$qemu_localedir" >> $config_host_mak
 echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
 echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
 
@@ -4135,7 +4137,7 @@ DIRS="$DIRS qapi-generated"
 DIRS="$DIRS libcacard libcacard/libcacard libcacard/trace"
 FILES="Makefile tests/tcg/Makefile qdict-test-data.txt"
 FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit"
-FILES="$FILES tests/tcg/lm32/Makefile libcacard/Makefile"
+FILES="$FILES tests/tcg/lm32/Makefile libcacard/Makefile po/Makefile"
 FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
 FILES="$FILES pc-bios/spapr-rtas/Makefile"
 FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile"
diff --git a/po/Makefile b/po/Makefile
new file mode 100644
index 0000000..0e2c11b
--- /dev/null
+++ b/po/Makefile
@@ -0,0 +1,43 @@
+# This makefile is very special as it's meant to build as part of the build
+# process and also within the source tree to update the translation files.
+
+VERSION=$(shell cat ../VERSION)
+TRANSLATIONS=de_DE
+SRCS=$(addsuffix .po, $(TRANSLATIONS))
+OBJS=$(addsuffix .mo, $(TRANSLATIONS))
+
+SRC_PATH=..
+
+-include ../config-host.mak
+
+vpath %.po $(SRC_PATH)/po
+
+all:
+	@echo Use 'make update' to update translation files
+	@echo or us 'make build' or 'make install' to build and install
+	@echo the translation files
+
+update: $(SRCS)
+
+build: $(OBJS)
+
+clean:
+	$(RM) $(OBJS)
+
+install: $(OBJS)
+	for obj in $(OBJS); do \
+	    base=`basename $$obj .mo`; \
+	    $(INSTALL) -d $(DESTDIR)$(prefix)/share/locale/$$base/LC_MESSAGES; \
+	    $(INSTALL) -m644 $$obj $(DESTDIR)$(prefix)/share/locale/$$base/LC_MESSAGES/qemu.mo; \
+	done
+
+%.mo:
+	@msgfmt -o $@ $(SRC_PATH)/po/`basename $@ .mo`.po
+
+messages.po: $(SRC_PATH)/ui/gtk.c
+	@xgettext -o $@ --foreign-user --package-name=QEMU --package-version=1.0.50 --msgid-bugs-address=qemu-devel@nongnu.org -k_ -C $<
+
+de_DE.po: messages.po $(SRC_PATH)/ui/gtk.c
+	@msgmerge $@ $< > $@.bak && mv $@.bak $@
+
+.PHONY: $(SRCS) clean all
diff --git a/po/de_DE.po b/po/de_DE.po
new file mode 100644
index 0000000..aa4ef42
--- /dev/null
+++ b/po/de_DE.po
@@ -0,0 +1,37 @@
+# SOME DESCRIPTIVE TITLE.
+# This file is put in the public domain.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: QEMU 1.0.50\n"
+"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
+"POT-Creation-Date: 2012-02-26 11:30-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../ui/gtk.c:769
+msgid "_File"
+msgstr "_File FIXME"
+
+#: ../ui/gtk.c:779
+msgid "_View"
+msgstr "_View FIXME"
+
+#: ../ui/gtk.c:781
+msgid "_Full Screen"
+msgstr "_Full Screen FIXME"
+
+#: ../ui/gtk.c:805
+msgid "_Grab Input"
+msgstr "_Grab Input FIXME"
+
+#: ../ui/gtk.c:831
+msgid "Show _Tabs"
+msgstr "Show _Tabs FIXME"
diff --git a/po/it.po b/po/it.po
new file mode 100644
index 0000000..85eeef9
--- /dev/null
+++ b/po/it.po
@@ -0,0 +1,37 @@
+# Italian translation for QEMU.
+# This file is put in the public domain.
+# Paolo Bonzini <pbonzini@redhat.com>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: QEMU 1.0.50\n"
+"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
+"POT-Creation-Date: 2012-02-26 11:30-0600\n"
+"PO-Revision-Date: 2012-02-27 08:23+0100\n"
+"Last-Translator: Paolo Bonzini <pbonzini@redhat.com>\n"
+"Language-Team: Italian <it@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+#: ../ui/gtk.c:769
+msgid "_File"
+msgstr "_File"
+
+#: ../ui/gtk.c:779
+msgid "_View"
+msgstr "_Visualizza"
+
+#: ../ui/gtk.c:781
+msgid "_Full Screen"
+msgstr "_Schermo intero"
+
+#: ../ui/gtk.c:805
+msgid "_Grab Input"
+msgstr "_Cattura input"
+
+#: ../ui/gtk.c:831
+msgid "Show _Tabs"
+msgstr "Mostra _tab"
diff --git a/po/messages.po b/po/messages.po
new file mode 100644
index 0000000..741e782
--- /dev/null
+++ b/po/messages.po
@@ -0,0 +1,37 @@
+# SOME DESCRIPTIVE TITLE.
+# This file is put in the public domain.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: QEMU 1.0.50\n"
+"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
+"POT-Creation-Date: 2012-02-26 11:30-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../ui/gtk.c:769
+msgid "_File"
+msgstr ""
+
+#: ../ui/gtk.c:779
+msgid "_View"
+msgstr ""
+
+#: ../ui/gtk.c:781
+msgid "_Full Screen"
+msgstr ""
+
+#: ../ui/gtk.c:805
+msgid "_Grab Input"
+msgstr ""
+
+#: ../ui/gtk.c:831
+msgid "Show _Tabs"
+msgstr ""
diff --git a/ui/gtk.c b/ui/gtk.c
index 5a5d8e2..aa80ef4 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -31,8 +31,12 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
  */
 
+#define GETTEXT_PACKAGE "qemu"
+#define LOCALEDIR "po"
+
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
+#include <glib/gi18n.h>
 #include <vte/vte.h>
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -940,7 +944,7 @@ static void gd_create_menus(GtkDisplayState *s)
     accel_group = gtk_accel_group_new();
     s->file_menu = gtk_menu_new();
     gtk_menu_set_accel_group(GTK_MENU(s->file_menu), accel_group);
-    s->file_menu_item = gtk_menu_item_new_with_mnemonic("_File");
+    s->file_menu_item = gtk_menu_item_new_with_mnemonic(_("_File"));
 
     s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
     gtk_stock_lookup(GTK_STOCK_QUIT, &item);
@@ -950,9 +954,9 @@ static void gd_create_menus(GtkDisplayState *s)
 
     s->view_menu = gtk_menu_new();
     gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group);
-    s->view_menu_item = gtk_menu_item_new_with_mnemonic("_View");
+    s->view_menu_item = gtk_menu_item_new_with_mnemonic(_("_View"));
 
-    s->full_screen_item = gtk_check_menu_item_new_with_mnemonic("_Full Screen");
+    s->full_screen_item = gtk_check_menu_item_new_with_mnemonic(_("_Full Screen"));
     gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->full_screen_item),
                                  "<QEMU>/View/Full Screen");
     gtk_accel_map_add_entry("<QEMU>/View/Full Screen", GDK_KEY_f, GDK_CONTROL_MASK | GDK_MOD1_MASK);
@@ -985,10 +989,10 @@ static void gd_create_menus(GtkDisplayState *s)
     separator = gtk_separator_menu_item_new();
     gtk_menu_append(GTK_MENU(s->view_menu), separator);
 
-    s->grab_on_hover_item = gtk_check_menu_item_new_with_mnemonic("Grab On _Hover");
+    s->grab_on_hover_item = gtk_check_menu_item_new_with_mnemonic(_("Grab On _Hover"));
     gtk_menu_append(GTK_MENU(s->view_menu), s->grab_on_hover_item);
 
-    s->grab_item = gtk_check_menu_item_new_with_mnemonic("_Grab Input");
+    s->grab_item = gtk_check_menu_item_new_with_mnemonic(_("_Grab Input"));
     gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->grab_item),
                                  "<QEMU>/View/Grab Input");
     gtk_accel_map_add_entry("<QEMU>/View/Grab Input", GDK_KEY_g, GDK_CONTROL_MASK | GDK_MOD1_MASK);
@@ -1014,7 +1018,7 @@ static void gd_create_menus(GtkDisplayState *s)
     separator = gtk_separator_menu_item_new();
     gtk_menu_append(GTK_MENU(s->view_menu), separator);
 
-    s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic("Show _Tabs");
+    s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic(_("Show _Tabs"));
     gtk_menu_append(GTK_MENU(s->view_menu), s->show_tabs_item);
 
     g_object_set_data(G_OBJECT(s->window), "accel_group", accel_group);
@@ -1051,6 +1055,10 @@ void gtk_display_init(DisplayState *ds)
     s->scale_y = 1.0;
     s->free_scale = FALSE;
 
+    setlocale(LC_ALL, "");
+    bindtextdomain("qemu", CONFIG_QEMU_LOCALEDIR);
+    textdomain("qemu");
+
     s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
 
     s->mouse_mode_notifier.notify = gd_mouse_mode_change;
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Qemu-devel] [PATCH 7/7] gtk: make default UI (v3)
  2012-09-05 19:18 [Qemu-devel] [PATCH 0/7] Add GTK UI to enable basic accessibility (v3) Anthony Liguori
                   ` (5 preceding siblings ...)
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 6/7] gtk: add translation support Anthony Liguori
@ 2012-09-05 19:18 ` Anthony Liguori
  6 siblings, 0 replies; 25+ messages in thread
From: Anthony Liguori @ 2012-09-05 19:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

A user can still enable SDL with '-sdl' or '-display sdl' but start making the
default display GTK by default.

I'd also like to deprecate the SDL display and remove it in a few releases.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
v1 -> v3:
 - fix -display gtk
 - fix -vnc none
---
 vl.c |   45 +++++++++++++++++++++++++++++++--------------
 1 files changed, 31 insertions(+), 14 deletions(-)

diff --git a/vl.c b/vl.c
index 7c577fa..47c5974 100644
--- a/vl.c
+++ b/vl.c
@@ -1837,6 +1837,13 @@ static DisplayType select_display(const char *p)
         fprintf(stderr, "Curses support is disabled\n");
         exit(1);
 #endif
+    } else if (strstart(p, "gtk", &opts)) {
+#ifdef CONFIG_GTK
+        display = DT_GTK;
+#else
+        fprintf(stderr, "GTK support is disabled\n");
+        exit(1);
+#endif
     } else if (strstart(p, "none", &opts)) {
         display = DT_NONE;
     } else {
@@ -3418,6 +3425,25 @@ int main(int argc, char **argv, char **envp)
             add_device_config(DEV_VIRTCON, "vc:80Cx24C");
     }
 
+    if (display_type == DT_DEFAULT && !display_remote) {
+#if defined(CONFIG_GTK)
+        display_type = DT_GTK;
+#elif defined(CONFIG_SDL) || defined(CONFIG_COCOA)
+        display_type = DT_SDL;
+#elif defined(CONFIG_VNC)
+        vnc_display = "localhost:0,to=99";
+        show_vnc_port = 1;
+#else
+        display_type = DT_NONE;
+#endif
+    }
+
+#if defined(CONFIG_GTK)
+    if (display_type == DT_GTK) {
+        early_gtk_display_init();
+    }
+#endif
+
     socket_init();
 
     if (qemu_opts_foreach(qemu_find_opts("chardev"), chardev_init_func, NULL, 1) != 0)
@@ -3637,20 +3663,6 @@ int main(int argc, char **argv, char **envp)
     /* just use the first displaystate for the moment */
     ds = get_displaystate();
 
-    if (using_spice)
-        display_remote++;
-    if (display_type == DT_DEFAULT && !display_remote) {
-#if defined(CONFIG_SDL) || defined(CONFIG_COCOA)
-        display_type = DT_SDL;
-#elif defined(CONFIG_VNC)
-        vnc_display = "localhost:0,to=99";
-        show_vnc_port = 1;
-#else
-        display_type = DT_NONE;
-#endif
-    }
-
-
     /* init local displays */
     switch (display_type) {
     case DT_NOGRAPHIC:
@@ -3669,6 +3681,11 @@ int main(int argc, char **argv, char **envp)
         cocoa_display_init(ds, full_screen);
         break;
 #endif
+#if defined(CONFIG_GTK)
+    case DT_GTK:
+        gtk_display_init(ds);
+        break;
+#endif
     default:
         break;
     }
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 4/7] gtk: add support for input grabbing (v2)
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 4/7] gtk: add support for input grabbing (v2) Anthony Liguori
@ 2012-09-05 19:37   ` Jan Kiszka
  2012-09-05 20:40     ` Anthony Liguori
  0 siblings, 1 reply; 25+ messages in thread
From: Jan Kiszka @ 2012-09-05 19:37 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1016 bytes --]

On 2012-09-05 21:18, Anthony Liguori wrote:
> There is a small deviation from SDL's behavior here.  Instead of Ctrl+Alt
> triggering grab, we now use Ctrl-Alt-g to trigger grab.
> 
> GTK will not accept Ctrl+Alt as an accelerator since it just consists of
> modifiers.  Having grab as a proper accelerator is important as it allows a user
> to override the accelerator for accessibility purposes.
> 
> We also are not automatically grabbing on left-click.  Besides the inability to
> tie mouse clicks to an accelerator, I think this behavior is hard to discover
> and since it only happens depending on the guest state, it can lead to confusing
> behavior.
> 
> This can be changed in the future if there's a strong resistence to dropping
> left-click-to-grab, but I think we're better off dropping it.
> 
> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
> ---
> v1 -> v2
>  - add a menu option for grab on hover (Jan)

Thanks. Are options like this persistent across VM starts?

Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 259 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2)
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2) Anthony Liguori
@ 2012-09-05 19:53   ` Blue Swirl
  2012-09-05 20:00     ` Eric Blake
  2012-09-05 20:38     ` Anthony Liguori
  2012-09-05 20:04   ` Stefan Weil
  2012-09-05 20:54   ` Jan Kiszka
  2 siblings, 2 replies; 25+ messages in thread
From: Blue Swirl @ 2012-09-05 19:53 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

On Wed, Sep 5, 2012 at 7:18 PM, Anthony Liguori <aliguori@us.ibm.com> wrote:
> This is minimalistic and just contains the basic widget infrastructure.  The GUI
> consists of a menu and a GtkNotebook.  To start with, the notebook has its tabs
> hidden which provides a UI that looks very similar to SDL with the exception of
> the menu bar.
>
> The menu bar allows a user to toggle the visibility of the tabs.  Cairo is used
> for rendering.
>
> I used gtk-vnc as a reference.  gtk-vnc solves the same basic problems as QEMU
> since it was originally written as a remote display for QEMU.  So for the most
> part, the approach to rendering and keyboard handling should be pretty solid for
> GTK.
>
> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
> ---
> v1 -> v2
>  - add gtk-vnc license
>  - fix key propagation
> ---
>  Makefile         |    2 +
>  configure        |   25 +++-
>  console.h        |    4 +
>  sysemu.h         |    1 +
>  ui/Makefile.objs |    1 +
>  ui/gtk.c         |  572 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 604 insertions(+), 1 deletions(-)
>  create mode 100644 ui/gtk.c
>
> diff --git a/Makefile b/Makefile
> index 1cd5bc8..9523e05 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -122,6 +122,8 @@ ui/cocoa.o: ui/cocoa.m
>
>  ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o hw/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
>
> +ui/gtk.o: QEMU_CFLAGS += $(GTK_CFLAGS) $(VTE_CFLAGS)
> +
>  ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
>
>  bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
> diff --git a/configure b/configure
> index d97fd81..586dbd3 100755
> --- a/configure
> +++ b/configure
> @@ -278,7 +278,7 @@ sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
>  # default flags for all hosts
>  QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
>  QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
> -QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
> +QEMU_CFLAGS="-Wredundant-decls $QEMU_CFLAGS"

Is this intentional? I hope not.

>  QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
>  QEMU_INCLUDES="-I. -I\$(SRC_PATH) -I\$(SRC_PATH)/fpu"
>  if test "$debug_info" = "yes"; then
> @@ -1635,6 +1635,23 @@ if test "$sparse" != "no" ; then
>  fi
>
>  ##########################################
> +# GTK probe
> +
> +if test "$gtk" != "no"; then
> +    if $pkg_config gtk+-2.0 --modversion >/dev/null 2>/dev/null && \
> +       $pkg_config vte --modversion >/dev/null 2>/dev/null; then
> +       gtk_cflags=`$pkg_config --cflags gtk+-2.0 2>/dev/null`
> +       gtk_libs=`$pkg_config --libs gtk+-2.0 2>/dev/null`
> +       vte_cflags=`$pkg_config --cflags vte 2>/dev/null`
> +       vte_libs=`$pkg_config --libs vte 2>/dev/null`
> +       libs_softmmu="$gtk_libs $vte_libs $libs_softmmu"
> +       gtk="yes"
> +    else
> +       gtk="no"
> +    fi
> +fi
> +
> +##########################################
>  # SDL probe
>
>  # Look for sdl configuration program (pkg-config or sdl-config).  Try
> @@ -3113,6 +3130,7 @@ if test "$darwin" = "yes" ; then
>      echo "Cocoa support     $cocoa"
>  fi
>  echo "SDL support       $sdl"
> +echo "GTK support       $gtk"
>  echo "curses support    $curses"
>  echo "curl support      $curl"
>  echo "mingw32 support   $mingw32"
> @@ -3390,6 +3408,11 @@ if test "$bluez" = "yes" ; then
>    echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
>  fi
>  echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
> +if test "$gtk" = "yes" ; then
> +  echo "CONFIG_GTK=y" >> $config_host_mak
> +  echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
> +  echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
> +fi
>  if test "$xen" = "yes" ; then
>    echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
>    echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
> diff --git a/console.h b/console.h
> index eb428f9..2bd4814 100644
> --- a/console.h
> +++ b/console.h
> @@ -401,4 +401,8 @@ static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
>  /* curses.c */
>  void curses_display_init(DisplayState *ds, int full_screen);
>
> +/* gtk.c */
> +void early_gtk_display_init(void);
> +void gtk_display_init(DisplayState *ds);
> +
>  #endif
> diff --git a/sysemu.h b/sysemu.h
> index 65552ac..09a8523 100644
> --- a/sysemu.h
> +++ b/sysemu.h
> @@ -93,6 +93,7 @@ typedef enum DisplayType
>      DT_DEFAULT,
>      DT_CURSES,
>      DT_SDL,
> +    DT_GTK,
>      DT_NOGRAPHIC,
>      DT_NONE,
>  } DisplayType;
> diff --git a/ui/Makefile.objs b/ui/Makefile.objs
> index adc07be..89f8d64 100644
> --- a/ui/Makefile.objs
> +++ b/ui/Makefile.objs
> @@ -12,3 +12,4 @@ common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
>  common-obj-$(CONFIG_COCOA) += cocoa.o
>  common-obj-$(CONFIG_CURSES) += curses.o
>  common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
> +common-obj-$(CONFIG_GTK) += gtk.o
> diff --git a/ui/gtk.c b/ui/gtk.c
> new file mode 100644
> index 0000000..e724956
> --- /dev/null
> +++ b/ui/gtk.c
> @@ -0,0 +1,572 @@
> +/*
> + * GTK UI
> + *
> + * Copyright IBM, Corp. 2012
> + *
> + * Authors:
> + *  Anthony Liguori   <aliguori@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + * Portions from gtk-vnc:
> + *
> + * GTK VNC Widget
> + *
> + * Copyright (C) 2006  Anthony Liguori <anthony@codemonkey.ws>
> + * Copyright (C) 2009-2010 Daniel P. Berrange <dan@berrange.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.0 of the License, or (at your option) any later version.
> + *
> + * This library 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
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA

Please use the recommended web version like other files.

> + */
> +
> +#include <gtk/gtk.h>
> +#include <gdk/gdkkeysyms.h>
> +#include <vte/vte.h>
> +#include <sys/types.h>
> +#include <sys/socket.h>
> +#include <sys/un.h>
> +#include <sys/wait.h>
> +#include <pty.h>
> +#include <math.h>
> +
> +#include "qemu-common.h"
> +#include "console.h"
> +#include "sysemu.h"
> +#include "qmp-commands.h"
> +#include "x_keymap.h"
> +#include "keymaps.h"
> +
> +//#define DEBUG_GTK
> +
> +#ifdef DEBUG_GTK
> +#define dprintf(fmt, ...) printf(fmt, ## __VA_ARGS__)

dprintf is actually defined by stdio.h. Either rename or #undef first.

> +#else
> +#define dprintf(fmt, ...) do { } while (0)
> +#endif
> +
> +typedef struct VirtualConsole
> +{
> +    GtkWidget *menu_item;
> +    GtkWidget *terminal;
> +    GtkWidget *scrolled_window;
> +    CharDriverState *chr;
> +    int fd;
> +} VirtualConsole;
> +
> +typedef struct GtkDisplayState
> +{
> +    GtkWidget *window;
> +
> +    GtkWidget *menu_bar;
> +
> +    GtkWidget *file_menu_item;
> +    GtkWidget *file_menu;
> +    GtkWidget *quit_item;
> +
> +    GtkWidget *view_menu_item;
> +    GtkWidget *view_menu;
> +    GtkWidget *vga_item;
> +
> +    GtkWidget *show_tabs_item;
> +
> +    GtkWidget *vbox;
> +    GtkWidget *notebook;
> +    GtkWidget *drawing_area;
> +    cairo_surface_t *surface;
> +    DisplayChangeListener dcl;
> +    DisplayState *ds;
> +    int button_mask;
> +    int last_x;
> +    int last_y;
> +
> +    double scale_x;
> +    double scale_y;
> +
> +    GdkCursor *null_cursor;
> +    Notifier mouse_mode_notifier;
> +} GtkDisplayState;
> +
> +static GtkDisplayState *global_state;
> +
> +/** Utility Functions **/
> +
> +static void gd_update_cursor(GtkDisplayState *s, gboolean override)
> +{
> +    GdkWindow *window;
> +    bool on_vga;
> +
> +    window = gtk_widget_get_window(GTK_WIDGET(s->drawing_area));
> +
> +    on_vga = (gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0);
> +
> +    if ((override || on_vga) && kbd_mouse_is_absolute()) {
> +        gdk_window_set_cursor(window, s->null_cursor);
> +    } else {
> +        gdk_window_set_cursor(window, NULL);
> +    }
> +}
> +
> +static void gd_update_caption(GtkDisplayState *s)
> +{
> +    const char *status = "";
> +    gchar *title;
> +
> +    if (!runstate_is_running()) {
> +        status = " [Stopped]";
> +    }
> +
> +    if (qemu_name) {
> +        title = g_strdup_printf("QEMU (%s)%s", qemu_name, status);
> +    } else {
> +        title = g_strdup_printf("QEMU%s", status);
> +    }
> +
> +    gtk_window_set_title(GTK_WINDOW(s->window), title);
> +
> +    g_free(title);
> +}
> +
> +/** DisplayState Callbacks **/
> +
> +static void gd_update(DisplayState *ds, int x, int y, int w, int h)
> +{
> +    GtkDisplayState *s = ds->opaque;
> +    int x1, x2, y1, y2;
> +
> +    dprintf("update(x=%d, y=%d, w=%d, h=%d)\n", x, y, w, h);
> +
> +    x1 = floor(x * s->scale_x);
> +    y1 = floor(y * s->scale_y);
> +
> +    x2 = ceil(x * s->scale_x + w * s->scale_x);
> +    y2 = ceil(y * s->scale_y + h * s->scale_y);
> +
> +    gtk_widget_queue_draw_area(s->drawing_area, x1, y1, (x2 - x1), (y2 - y1));
> +}
> +
> +static void gd_refresh(DisplayState *ds)
> +{
> +    vga_hw_update();
> +}
> +
> +static void gd_resize(DisplayState *ds)
> +{
> +    GtkDisplayState *s = ds->opaque;
> +    cairo_format_t kind;
> +    int stride;
> +
> +    dprintf("resize(width=%d, height=%d)\n",
> +            ds->surface->width, ds->surface->height);
> +
> +    if (s->surface) {
> +        cairo_surface_destroy(s->surface);
> +    }
> +
> +    switch (ds->surface->pf.bits_per_pixel) {
> +    case 8:
> +        kind = CAIRO_FORMAT_A8;
> +        break;
> +    case 16:
> +        kind = CAIRO_FORMAT_RGB16_565;
> +        break;
> +    case 32:
> +        kind = CAIRO_FORMAT_RGB24;
> +        break;
> +    default:
> +        g_assert_not_reached();
> +        break;
> +    }
> +
> +    stride = cairo_format_stride_for_width(kind, ds->surface->width);
> +    g_assert_cmpint(ds->surface->linesize, ==, stride);
> +
> +    s->surface = cairo_image_surface_create_for_data(ds->surface->data,
> +                                                     kind,
> +                                                     ds->surface->width,
> +                                                     ds->surface->height,
> +                                                     ds->surface->linesize);
> +
> +    gtk_widget_set_size_request(s->drawing_area,
> +                                ds->surface->width * s->scale_x,
> +                                ds->surface->height * s->scale_y);
> +}
> +
> +/** QEMU Events **/
> +
> +static void gd_change_runstate(void *opaque, int running, RunState state)
> +{
> +    GtkDisplayState *s = opaque;
> +
> +    gd_update_caption(s);
> +}
> +
> +static void gd_mouse_mode_change(Notifier *notify, void *data)
> +{
> +    gd_update_cursor(container_of(notify, GtkDisplayState, mouse_mode_notifier),
> +                     FALSE);
> +}
> +
> +/** GTK Events **/
> +
> +static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
> +                                void *opaque)
> +{
> +    if (!no_quit) {
> +        qmp_quit(NULL);
> +        return FALSE;
> +    }
> +
> +    return TRUE;
> +}
> +
> +static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
> +{
> +    GtkDisplayState *s = opaque;
> +    int ww, wh;
> +    int fbw, fbh;
> +
> +    fbw = s->ds->surface->width;
> +    fbh = s->ds->surface->height;
> +
> +    gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
> +
> +    cairo_rectangle(cr, 0, 0, ww, wh);
> +
> +    if (ww != fbw || wh != fbh) {
> +        s->scale_x = (double)ww / fbw;
> +        s->scale_y = (double)wh / fbh;
> +        cairo_scale(cr, s->scale_x, s->scale_y);
> +    } else {
> +        s->scale_x = 1.0;
> +        s->scale_y = 1.0;
> +    }
> +
> +    cairo_set_source_surface(cr, s->surface, 0, 0);
> +    cairo_paint(cr);
> +
> +    return TRUE;
> +}
> +
> +static gboolean gd_expose_event(GtkWidget *widget, GdkEventExpose *expose,
> +                                void *opaque)
> +{
> +    cairo_t *cr;
> +    gboolean ret;
> +
> +    cr = gdk_cairo_create(gtk_widget_get_window(widget));
> +    cairo_rectangle(cr,
> +                    expose->area.x,
> +                    expose->area.y,
> +                    expose->area.width,
> +                    expose->area.height);
> +    cairo_clip(cr);
> +
> +    ret = gd_draw_event(widget, cr, opaque);
> +
> +    cairo_destroy(cr);
> +
> +    return ret;
> +}
> +
> +static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
> +                                void *opaque)
> +{
> +    GtkDisplayState *s = opaque;
> +    int dx, dy;
> +    int x, y;
> +
> +    x = motion->x / s->scale_x;
> +    y = motion->y / s->scale_y;
> +
> +    if (kbd_mouse_is_absolute()) {
> +        dx = x * 0x7FFF / (s->ds->surface->width - 1);
> +        dy = y * 0x7FFF / (s->ds->surface->height - 1);
> +    } else if (s->last_x == -1 || s->last_y == -1) {
> +        dx = 0;
> +        dy = 0;
> +    } else {
> +        dx = x - s->last_x;
> +        dy = y - s->last_y;
> +    }
> +
> +    s->last_x = x;
> +    s->last_y = y;
> +
> +    if (kbd_mouse_is_absolute()) {
> +        kbd_mouse_event(dx, dy, 0, s->button_mask);
> +    }
> +
> +    return TRUE;
> +}
> +
> +static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button,
> +                                void *opaque)
> +{
> +    GtkDisplayState *s = opaque;
> +    int dx, dy;
> +    int n;
> +
> +    if (button->button == 1) {
> +        n = 0x01;
> +    } else if (button->button == 2) {
> +        n = 0x04;
> +    } else if (button->button == 3) {
> +        n = 0x02;
> +    } else {
> +        n = 0x00;
> +    }
> +
> +    if (button->type == GDK_BUTTON_PRESS) {
> +        s->button_mask |= n;
> +    } else if (button->type == GDK_BUTTON_RELEASE) {
> +        s->button_mask &= ~n;
> +    }
> +
> +    if (kbd_mouse_is_absolute()) {
> +        dx = s->last_x * 0x7FFF / (s->ds->surface->width - 1);
> +        dy = s->last_y * 0x7FFF / (s->ds->surface->height - 1);
> +    } else {
> +        dx = 0;
> +        dy = 0;
> +    }
> +
> +    kbd_mouse_event(dx, dy, 0, s->button_mask);
> +
> +    return TRUE;
> +}
> +
> +static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
> +{
> +    int gdk_keycode;
> +    int qemu_keycode;
> +
> +    gdk_keycode = key->hardware_keycode;
> +
> +    if (gdk_keycode < 9) {
> +        qemu_keycode = 0;
> +    } else if (gdk_keycode < 97) {
> +        qemu_keycode = gdk_keycode - 8;
> +    } else if (gdk_keycode < 158) {
> +        qemu_keycode = translate_evdev_keycode(gdk_keycode - 97);
> +    } else if (gdk_keycode == 208) { /* Hiragana_Katakana */
> +        qemu_keycode = 0x70;
> +    } else if (gdk_keycode == 211) { /* backslash */
> +        qemu_keycode = 0x73;
> +    } else {
> +        qemu_keycode = 0;
> +    }
> +
> +    dprintf("translated GDK keycode %d to QEMU keycode %d (%s)\n",
> +            gdk_keycode, qemu_keycode,
> +            (key->type == GDK_KEY_PRESS) ? "down" : "up");
> +
> +    if (qemu_keycode & SCANCODE_GREY) {
> +        kbd_put_keycode(SCANCODE_EMUL0);
> +    }
> +
> +    if (key->type == GDK_KEY_PRESS) {
> +        kbd_put_keycode(qemu_keycode & SCANCODE_KEYCODEMASK);
> +    } else if (key->type == GDK_KEY_RELEASE) {
> +        kbd_put_keycode(qemu_keycode | SCANCODE_UP);
> +    } else {
> +        g_assert_not_reached();
> +    }
> +
> +    return TRUE;
> +}
> +
> +/** Window Menu Actions **/
> +
> +static void gd_menu_quit(GtkMenuItem *item, void *opaque)
> +{
> +    qmp_quit(NULL);
> +}
> +
> +static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque)
> +{
> +    GtkDisplayState *s = opaque;
> +
> +    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vga_item))) {
> +        gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), 0);
> +    }
> +}
> +
> +static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque)
> +{
> +    GtkDisplayState *s = opaque;
> +
> +    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->show_tabs_item))) {
> +        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), TRUE);
> +    } else {
> +        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
> +    }
> +}
> +
> +static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
> +                           gpointer data)
> +{
> +    GtkDisplayState *s = data;
> +
> +    if (!gtk_widget_get_realized(s->notebook)) {
> +        return;
> +    }
> +
> +    gd_update_cursor(s, TRUE);
> +}
> +
> +void early_gtk_display_init(void)
> +{
> +}
> +
> +/** Window Creation **/
> +
> +static void gd_connect_signals(GtkDisplayState *s)
> +{
> +    g_signal_connect(s->show_tabs_item, "activate",
> +                     G_CALLBACK(gd_menu_show_tabs), s);
> +
> +    g_signal_connect(s->window, "delete-event",
> +                     G_CALLBACK(gd_window_close), s);
> +
> +    g_signal_connect(s->drawing_area, "expose-event",
> +                     G_CALLBACK(gd_expose_event), s);
> +    g_signal_connect(s->drawing_area, "motion-notify-event",
> +                     G_CALLBACK(gd_motion_event), s);
> +    g_signal_connect(s->drawing_area, "button-press-event",
> +                     G_CALLBACK(gd_button_event), s);
> +    g_signal_connect(s->drawing_area, "button-release-event",
> +                     G_CALLBACK(gd_button_event), s);
> +    g_signal_connect(s->drawing_area, "key-press-event",
> +                     G_CALLBACK(gd_key_event), s);
> +    g_signal_connect(s->drawing_area, "key-release-event",
> +                     G_CALLBACK(gd_key_event), s);
> +
> +    g_signal_connect(s->quit_item, "activate",
> +                     G_CALLBACK(gd_menu_quit), s);
> +    g_signal_connect(s->vga_item, "activate",
> +                     G_CALLBACK(gd_menu_switch_vc), s);
> +    g_signal_connect(s->notebook, "switch-page",
> +                     G_CALLBACK(gd_change_page), s);
> +}
> +
> +static void gd_create_menus(GtkDisplayState *s)
> +{
> +    GtkStockItem item;
> +    GtkAccelGroup *accel_group;
> +    GSList *group = NULL;
> +    GtkWidget *separator;
> +
> +    accel_group = gtk_accel_group_new();
> +    s->file_menu = gtk_menu_new();
> +    gtk_menu_set_accel_group(GTK_MENU(s->file_menu), accel_group);
> +    s->file_menu_item = gtk_menu_item_new_with_mnemonic("_File");
> +
> +    s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
> +    gtk_stock_lookup(GTK_STOCK_QUIT, &item);
> +    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item),
> +                                 "<QEMU>/File/Quit");
> +    gtk_accel_map_add_entry("<QEMU>/File/Quit", item.keyval, item.modifier);
> +
> +    s->view_menu = gtk_menu_new();
> +    gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group);
> +    s->view_menu_item = gtk_menu_item_new_with_mnemonic("_View");
> +
> +    separator = gtk_separator_menu_item_new();
> +    gtk_menu_append(GTK_MENU(s->view_menu), separator);
> +
> +    s->vga_item = gtk_radio_menu_item_new_with_mnemonic(group, "_VGA");
> +    group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(s->vga_item));
> +    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->vga_item),
> +                                 "<QEMU>/View/VGA");
> +    gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK);
> +    gtk_menu_append(GTK_MENU(s->view_menu), s->vga_item);
> +
> +    separator = gtk_separator_menu_item_new();
> +    gtk_menu_append(GTK_MENU(s->view_menu), separator);
> +
> +    s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic("Show _Tabs");
> +    gtk_menu_append(GTK_MENU(s->view_menu), s->show_tabs_item);
> +
> +    g_object_set_data(G_OBJECT(s->window), "accel_group", accel_group);
> +    gtk_window_add_accel_group(GTK_WINDOW(s->window), accel_group);
> +
> +    gtk_menu_append(GTK_MENU(s->file_menu), s->quit_item);
> +    gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->file_menu_item), s->file_menu);
> +    gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->file_menu_item);
> +
> +    gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->view_menu_item), s->view_menu);
> +    gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->view_menu_item);
> +}
> +
> +void gtk_display_init(DisplayState *ds)
> +{
> +    GtkDisplayState *s = g_malloc0(sizeof(*s));
> +
> +    gtk_init(NULL, NULL);
> +
> +    ds->opaque = s;
> +    s->ds = ds;
> +    s->dcl.dpy_update = gd_update;
> +    s->dcl.dpy_resize = gd_resize;
> +    s->dcl.dpy_refresh = gd_refresh;
> +    register_displaychangelistener(ds, &s->dcl);
> +
> +    s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
> +    s->vbox = gtk_vbox_new(FALSE, 0);
> +    s->notebook = gtk_notebook_new();
> +    s->drawing_area = gtk_drawing_area_new();
> +    s->menu_bar = gtk_menu_bar_new();
> +
> +    s->scale_x = 1.0;
> +    s->scale_y = 1.0;
> +
> +    s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
> +
> +    s->mouse_mode_notifier.notify = gd_mouse_mode_change;
> +    qemu_add_mouse_mode_change_notifier(&s->mouse_mode_notifier);
> +    qemu_add_vm_change_state_handler(gd_change_runstate, s);
> +
> +    gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), s->drawing_area, gtk_label_new("VGA"));
> +
> +    gd_create_menus(s);
> +
> +    gd_connect_signals(s);
> +
> +    gtk_widget_add_events(s->drawing_area,
> +                          GDK_POINTER_MOTION_MASK |
> +                          GDK_BUTTON_PRESS_MASK |
> +                          GDK_BUTTON_RELEASE_MASK |
> +                          GDK_BUTTON_MOTION_MASK |
> +                          GDK_SCROLL_MASK |
> +                          GDK_KEY_PRESS_MASK);
> +    gtk_widget_set_double_buffered(s->drawing_area, FALSE);
> +    gtk_widget_set_can_focus(s->drawing_area, TRUE);
> +
> +    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
> +    gtk_notebook_set_show_border(GTK_NOTEBOOK(s->notebook), FALSE);
> +
> +    gtk_window_set_resizable(GTK_WINDOW(s->window), FALSE);
> +
> +    gd_update_caption(s);
> +
> +    gtk_box_pack_start(GTK_BOX(s->vbox), s->menu_bar, FALSE, TRUE, 0);
> +    gtk_box_pack_start(GTK_BOX(s->vbox), s->notebook, TRUE, TRUE, 0);
> +
> +    gtk_container_add(GTK_CONTAINER(s->window), s->vbox);
> +
> +    gtk_widget_show_all(s->window);
> +
> +    global_state = s;
> +}
> --
> 1.7.5.4
>
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2)
  2012-09-05 19:53   ` Blue Swirl
@ 2012-09-05 20:00     ` Eric Blake
  2012-09-05 20:38     ` Anthony Liguori
  1 sibling, 0 replies; 25+ messages in thread
From: Eric Blake @ 2012-09-05 20:00 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Anthony Liguori, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 874 bytes --]

On 09/05/2012 01:53 PM, Blue Swirl wrote:
> On Wed, Sep 5, 2012 at 7:18 PM, Anthony Liguori <aliguori@us.ibm.com> wrote:
>> This is minimalistic and just contains the basic widget infrastructure.  The GUI
>> consists of a menu and a GtkNotebook.  To start with, the notebook has its tabs
>> hidden which provides a UI that looks very similar to SDL with the exception of
>> the menu bar.
>>

>> +#ifdef DEBUG_GTK
>> +#define dprintf(fmt, ...) printf(fmt, ## __VA_ARGS__)
> 
> dprintf is actually defined by stdio.h. Either rename or #undef first.

Worse than that, dprintf() is mandated by POSIX 2008, and you are using
a reserved name with different meaning, which can give undefined
behavior.  Your best bet is to use a name other than dprintf.

-- 
Eric Blake   eblake@redhat.com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 617 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2)
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2) Anthony Liguori
  2012-09-05 19:53   ` Blue Swirl
@ 2012-09-05 20:04   ` Stefan Weil
  2012-09-05 20:39     ` Anthony Liguori
  2012-09-05 20:45     ` Jan Kiszka
  2012-09-05 20:54   ` Jan Kiszka
  2 siblings, 2 replies; 25+ messages in thread
From: Stefan Weil @ 2012-09-05 20:04 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

Am 05.09.2012 21:18, schrieb Anthony Liguori:
> This is minimalistic and just contains the basic widget infrastructure.  The GUI
> consists of a menu and a GtkNotebook.  To start with, the notebook has its tabs
> hidden which provides a UI that looks very similar to SDL with the exception of
> the menu bar.
>
> The menu bar allows a user to toggle the visibility of the tabs.  Cairo is used
> for rendering.
>
> I used gtk-vnc as a reference.  gtk-vnc solves the same basic problems as QEMU
> since it was originally written as a remote display for QEMU.  So for the most
> part, the approach to rendering and keyboard handling should be pretty solid for
> GTK.
>
> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
> ---
> v1 ->  v2
>   - add gtk-vnc license
>   - fix key propagation
> ---
>   Makefile         |    2 +
>   configure        |   25 +++-
>   console.h        |    4 +
>   sysemu.h         |    1 +
>   ui/Makefile.objs |    1 +
>   ui/gtk.c         |  572 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   6 files changed, 604 insertions(+), 1 deletions(-)
>   create mode 100644 ui/gtk.c
>

Hi Anthony,

I tested the previous version of your series and noticed that the
menu accelerators (especially for file/quit) which are still part of
this new patch are a bad idea.

Just run a system emulation, start some GUI program in the emulation
and press Ctrl-Q: you won't terminate the GUI program, but terminate
QEMU!

Cheers,

Stefan W.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2)
  2012-09-05 19:53   ` Blue Swirl
  2012-09-05 20:00     ` Eric Blake
@ 2012-09-05 20:38     ` Anthony Liguori
  2012-09-05 21:00       ` Blue Swirl
  1 sibling, 1 reply; 25+ messages in thread
From: Anthony Liguori @ 2012-09-05 20:38 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

Blue Swirl <blauwirbel@gmail.com> writes:

> On Wed, Sep 5, 2012 at 7:18 PM, Anthony Liguori <aliguori@us.ibm.com> wrote:
>> This is minimalistic and just contains the basic widget infrastructure.  The GUI
>> consists of a menu and a GtkNotebook.  To start with, the notebook has its tabs
>> hidden which provides a UI that looks very similar to SDL with the exception of
>> the menu bar.
>>
>> The menu bar allows a user to toggle the visibility of the tabs.  Cairo is used
>> for rendering.
>>
>> I used gtk-vnc as a reference.  gtk-vnc solves the same basic problems as QEMU
>> since it was originally written as a remote display for QEMU.  So for the most
>> part, the approach to rendering and keyboard handling should be pretty solid for
>> GTK.
>>
>> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
>> ---
>> v1 -> v2
>>  - add gtk-vnc license
>>  - fix key propagation
>> ---
>>  Makefile         |    2 +
>>  configure        |   25 +++-
>>  console.h        |    4 +
>>  sysemu.h         |    1 +
>>  ui/Makefile.objs |    1 +
>>  ui/gtk.c         |  572 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  6 files changed, 604 insertions(+), 1 deletions(-)
>>  create mode 100644 ui/gtk.c
>>
>> diff --git a/Makefile b/Makefile
>> index 1cd5bc8..9523e05 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -122,6 +122,8 @@ ui/cocoa.o: ui/cocoa.m
>>
>>  ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o hw/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
>>
>> +ui/gtk.o: QEMU_CFLAGS += $(GTK_CFLAGS) $(VTE_CFLAGS)
>> +
>>  ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
>>
>>  bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
>> diff --git a/configure b/configure
>> index d97fd81..586dbd3 100755
>> --- a/configure
>> +++ b/configure
>> @@ -278,7 +278,7 @@ sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
>>  # default flags for all hosts
>>  QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
>>  QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
>> -QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
>> +QEMU_CFLAGS="-Wredundant-decls $QEMU_CFLAGS"
>
> Is this intentional? I hope not.

I forgot to split this out into a separate patch but yes, this is
intentional.  GTK won't build with -Wstrict-prototypes.

Regards,

Anthony Liguori

>
>>  QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
>>  QEMU_INCLUDES="-I. -I\$(SRC_PATH) -I\$(SRC_PATH)/fpu"
>>  if test "$debug_info" = "yes"; then
>> @@ -1635,6 +1635,23 @@ if test "$sparse" != "no" ; then
>>  fi
>>
>>  ##########################################
>> +# GTK probe
>> +
>> +if test "$gtk" != "no"; then
>> +    if $pkg_config gtk+-2.0 --modversion >/dev/null 2>/dev/null && \
>> +       $pkg_config vte --modversion >/dev/null 2>/dev/null; then
>> +       gtk_cflags=`$pkg_config --cflags gtk+-2.0 2>/dev/null`
>> +       gtk_libs=`$pkg_config --libs gtk+-2.0 2>/dev/null`
>> +       vte_cflags=`$pkg_config --cflags vte 2>/dev/null`
>> +       vte_libs=`$pkg_config --libs vte 2>/dev/null`
>> +       libs_softmmu="$gtk_libs $vte_libs $libs_softmmu"
>> +       gtk="yes"
>> +    else
>> +       gtk="no"
>> +    fi
>> +fi
>> +
>> +##########################################
>>  # SDL probe
>>
>>  # Look for sdl configuration program (pkg-config or sdl-config).  Try
>> @@ -3113,6 +3130,7 @@ if test "$darwin" = "yes" ; then
>>      echo "Cocoa support     $cocoa"
>>  fi
>>  echo "SDL support       $sdl"
>> +echo "GTK support       $gtk"
>>  echo "curses support    $curses"
>>  echo "curl support      $curl"
>>  echo "mingw32 support   $mingw32"
>> @@ -3390,6 +3408,11 @@ if test "$bluez" = "yes" ; then
>>    echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
>>  fi
>>  echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
>> +if test "$gtk" = "yes" ; then
>> +  echo "CONFIG_GTK=y" >> $config_host_mak
>> +  echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
>> +  echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
>> +fi
>>  if test "$xen" = "yes" ; then
>>    echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
>>    echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
>> diff --git a/console.h b/console.h
>> index eb428f9..2bd4814 100644
>> --- a/console.h
>> +++ b/console.h
>> @@ -401,4 +401,8 @@ static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
>>  /* curses.c */
>>  void curses_display_init(DisplayState *ds, int full_screen);
>>
>> +/* gtk.c */
>> +void early_gtk_display_init(void);
>> +void gtk_display_init(DisplayState *ds);
>> +
>>  #endif
>> diff --git a/sysemu.h b/sysemu.h
>> index 65552ac..09a8523 100644
>> --- a/sysemu.h
>> +++ b/sysemu.h
>> @@ -93,6 +93,7 @@ typedef enum DisplayType
>>      DT_DEFAULT,
>>      DT_CURSES,
>>      DT_SDL,
>> +    DT_GTK,
>>      DT_NOGRAPHIC,
>>      DT_NONE,
>>  } DisplayType;
>> diff --git a/ui/Makefile.objs b/ui/Makefile.objs
>> index adc07be..89f8d64 100644
>> --- a/ui/Makefile.objs
>> +++ b/ui/Makefile.objs
>> @@ -12,3 +12,4 @@ common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
>>  common-obj-$(CONFIG_COCOA) += cocoa.o
>>  common-obj-$(CONFIG_CURSES) += curses.o
>>  common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
>> +common-obj-$(CONFIG_GTK) += gtk.o
>> diff --git a/ui/gtk.c b/ui/gtk.c
>> new file mode 100644
>> index 0000000..e724956
>> --- /dev/null
>> +++ b/ui/gtk.c
>> @@ -0,0 +1,572 @@
>> +/*
>> + * GTK UI
>> + *
>> + * Copyright IBM, Corp. 2012
>> + *
>> + * Authors:
>> + *  Anthony Liguori   <aliguori@us.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>> + * See the COPYING file in the top-level directory.
>> + *
>> + * Portions from gtk-vnc:
>> + *
>> + * GTK VNC Widget
>> + *
>> + * Copyright (C) 2006  Anthony Liguori <anthony@codemonkey.ws>
>> + * Copyright (C) 2009-2010 Daniel P. Berrange <dan@berrange.com>
>> + *
>> + * This library is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2.0 of the License, or (at your option) any later version.
>> + *
>> + * This library 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
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with this library; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
>
> Please use the recommended web version like other files.
>
>> + */
>> +
>> +#include <gtk/gtk.h>
>> +#include <gdk/gdkkeysyms.h>
>> +#include <vte/vte.h>
>> +#include <sys/types.h>
>> +#include <sys/socket.h>
>> +#include <sys/un.h>
>> +#include <sys/wait.h>
>> +#include <pty.h>
>> +#include <math.h>
>> +
>> +#include "qemu-common.h"
>> +#include "console.h"
>> +#include "sysemu.h"
>> +#include "qmp-commands.h"
>> +#include "x_keymap.h"
>> +#include "keymaps.h"
>> +
>> +//#define DEBUG_GTK
>> +
>> +#ifdef DEBUG_GTK
>> +#define dprintf(fmt, ...) printf(fmt, ## __VA_ARGS__)
>
> dprintf is actually defined by stdio.h. Either rename or #undef first.
>
>> +#else
>> +#define dprintf(fmt, ...) do { } while (0)
>> +#endif
>> +
>> +typedef struct VirtualConsole
>> +{
>> +    GtkWidget *menu_item;
>> +    GtkWidget *terminal;
>> +    GtkWidget *scrolled_window;
>> +    CharDriverState *chr;
>> +    int fd;
>> +} VirtualConsole;
>> +
>> +typedef struct GtkDisplayState
>> +{
>> +    GtkWidget *window;
>> +
>> +    GtkWidget *menu_bar;
>> +
>> +    GtkWidget *file_menu_item;
>> +    GtkWidget *file_menu;
>> +    GtkWidget *quit_item;
>> +
>> +    GtkWidget *view_menu_item;
>> +    GtkWidget *view_menu;
>> +    GtkWidget *vga_item;
>> +
>> +    GtkWidget *show_tabs_item;
>> +
>> +    GtkWidget *vbox;
>> +    GtkWidget *notebook;
>> +    GtkWidget *drawing_area;
>> +    cairo_surface_t *surface;
>> +    DisplayChangeListener dcl;
>> +    DisplayState *ds;
>> +    int button_mask;
>> +    int last_x;
>> +    int last_y;
>> +
>> +    double scale_x;
>> +    double scale_y;
>> +
>> +    GdkCursor *null_cursor;
>> +    Notifier mouse_mode_notifier;
>> +} GtkDisplayState;
>> +
>> +static GtkDisplayState *global_state;
>> +
>> +/** Utility Functions **/
>> +
>> +static void gd_update_cursor(GtkDisplayState *s, gboolean override)
>> +{
>> +    GdkWindow *window;
>> +    bool on_vga;
>> +
>> +    window = gtk_widget_get_window(GTK_WIDGET(s->drawing_area));
>> +
>> +    on_vga = (gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0);
>> +
>> +    if ((override || on_vga) && kbd_mouse_is_absolute()) {
>> +        gdk_window_set_cursor(window, s->null_cursor);
>> +    } else {
>> +        gdk_window_set_cursor(window, NULL);
>> +    }
>> +}
>> +
>> +static void gd_update_caption(GtkDisplayState *s)
>> +{
>> +    const char *status = "";
>> +    gchar *title;
>> +
>> +    if (!runstate_is_running()) {
>> +        status = " [Stopped]";
>> +    }
>> +
>> +    if (qemu_name) {
>> +        title = g_strdup_printf("QEMU (%s)%s", qemu_name, status);
>> +    } else {
>> +        title = g_strdup_printf("QEMU%s", status);
>> +    }
>> +
>> +    gtk_window_set_title(GTK_WINDOW(s->window), title);
>> +
>> +    g_free(title);
>> +}
>> +
>> +/** DisplayState Callbacks **/
>> +
>> +static void gd_update(DisplayState *ds, int x, int y, int w, int h)
>> +{
>> +    GtkDisplayState *s = ds->opaque;
>> +    int x1, x2, y1, y2;
>> +
>> +    dprintf("update(x=%d, y=%d, w=%d, h=%d)\n", x, y, w, h);
>> +
>> +    x1 = floor(x * s->scale_x);
>> +    y1 = floor(y * s->scale_y);
>> +
>> +    x2 = ceil(x * s->scale_x + w * s->scale_x);
>> +    y2 = ceil(y * s->scale_y + h * s->scale_y);
>> +
>> +    gtk_widget_queue_draw_area(s->drawing_area, x1, y1, (x2 - x1), (y2 - y1));
>> +}
>> +
>> +static void gd_refresh(DisplayState *ds)
>> +{
>> +    vga_hw_update();
>> +}
>> +
>> +static void gd_resize(DisplayState *ds)
>> +{
>> +    GtkDisplayState *s = ds->opaque;
>> +    cairo_format_t kind;
>> +    int stride;
>> +
>> +    dprintf("resize(width=%d, height=%d)\n",
>> +            ds->surface->width, ds->surface->height);
>> +
>> +    if (s->surface) {
>> +        cairo_surface_destroy(s->surface);
>> +    }
>> +
>> +    switch (ds->surface->pf.bits_per_pixel) {
>> +    case 8:
>> +        kind = CAIRO_FORMAT_A8;
>> +        break;
>> +    case 16:
>> +        kind = CAIRO_FORMAT_RGB16_565;
>> +        break;
>> +    case 32:
>> +        kind = CAIRO_FORMAT_RGB24;
>> +        break;
>> +    default:
>> +        g_assert_not_reached();
>> +        break;
>> +    }
>> +
>> +    stride = cairo_format_stride_for_width(kind, ds->surface->width);
>> +    g_assert_cmpint(ds->surface->linesize, ==, stride);
>> +
>> +    s->surface = cairo_image_surface_create_for_data(ds->surface->data,
>> +                                                     kind,
>> +                                                     ds->surface->width,
>> +                                                     ds->surface->height,
>> +                                                     ds->surface->linesize);
>> +
>> +    gtk_widget_set_size_request(s->drawing_area,
>> +                                ds->surface->width * s->scale_x,
>> +                                ds->surface->height * s->scale_y);
>> +}
>> +
>> +/** QEMU Events **/
>> +
>> +static void gd_change_runstate(void *opaque, int running, RunState state)
>> +{
>> +    GtkDisplayState *s = opaque;
>> +
>> +    gd_update_caption(s);
>> +}
>> +
>> +static void gd_mouse_mode_change(Notifier *notify, void *data)
>> +{
>> +    gd_update_cursor(container_of(notify, GtkDisplayState, mouse_mode_notifier),
>> +                     FALSE);
>> +}
>> +
>> +/** GTK Events **/
>> +
>> +static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
>> +                                void *opaque)
>> +{
>> +    if (!no_quit) {
>> +        qmp_quit(NULL);
>> +        return FALSE;
>> +    }
>> +
>> +    return TRUE;
>> +}
>> +
>> +static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
>> +{
>> +    GtkDisplayState *s = opaque;
>> +    int ww, wh;
>> +    int fbw, fbh;
>> +
>> +    fbw = s->ds->surface->width;
>> +    fbh = s->ds->surface->height;
>> +
>> +    gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
>> +
>> +    cairo_rectangle(cr, 0, 0, ww, wh);
>> +
>> +    if (ww != fbw || wh != fbh) {
>> +        s->scale_x = (double)ww / fbw;
>> +        s->scale_y = (double)wh / fbh;
>> +        cairo_scale(cr, s->scale_x, s->scale_y);
>> +    } else {
>> +        s->scale_x = 1.0;
>> +        s->scale_y = 1.0;
>> +    }
>> +
>> +    cairo_set_source_surface(cr, s->surface, 0, 0);
>> +    cairo_paint(cr);
>> +
>> +    return TRUE;
>> +}
>> +
>> +static gboolean gd_expose_event(GtkWidget *widget, GdkEventExpose *expose,
>> +                                void *opaque)
>> +{
>> +    cairo_t *cr;
>> +    gboolean ret;
>> +
>> +    cr = gdk_cairo_create(gtk_widget_get_window(widget));
>> +    cairo_rectangle(cr,
>> +                    expose->area.x,
>> +                    expose->area.y,
>> +                    expose->area.width,
>> +                    expose->area.height);
>> +    cairo_clip(cr);
>> +
>> +    ret = gd_draw_event(widget, cr, opaque);
>> +
>> +    cairo_destroy(cr);
>> +
>> +    return ret;
>> +}
>> +
>> +static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
>> +                                void *opaque)
>> +{
>> +    GtkDisplayState *s = opaque;
>> +    int dx, dy;
>> +    int x, y;
>> +
>> +    x = motion->x / s->scale_x;
>> +    y = motion->y / s->scale_y;
>> +
>> +    if (kbd_mouse_is_absolute()) {
>> +        dx = x * 0x7FFF / (s->ds->surface->width - 1);
>> +        dy = y * 0x7FFF / (s->ds->surface->height - 1);
>> +    } else if (s->last_x == -1 || s->last_y == -1) {
>> +        dx = 0;
>> +        dy = 0;
>> +    } else {
>> +        dx = x - s->last_x;
>> +        dy = y - s->last_y;
>> +    }
>> +
>> +    s->last_x = x;
>> +    s->last_y = y;
>> +
>> +    if (kbd_mouse_is_absolute()) {
>> +        kbd_mouse_event(dx, dy, 0, s->button_mask);
>> +    }
>> +
>> +    return TRUE;
>> +}
>> +
>> +static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button,
>> +                                void *opaque)
>> +{
>> +    GtkDisplayState *s = opaque;
>> +    int dx, dy;
>> +    int n;
>> +
>> +    if (button->button == 1) {
>> +        n = 0x01;
>> +    } else if (button->button == 2) {
>> +        n = 0x04;
>> +    } else if (button->button == 3) {
>> +        n = 0x02;
>> +    } else {
>> +        n = 0x00;
>> +    }
>> +
>> +    if (button->type == GDK_BUTTON_PRESS) {
>> +        s->button_mask |= n;
>> +    } else if (button->type == GDK_BUTTON_RELEASE) {
>> +        s->button_mask &= ~n;
>> +    }
>> +
>> +    if (kbd_mouse_is_absolute()) {
>> +        dx = s->last_x * 0x7FFF / (s->ds->surface->width - 1);
>> +        dy = s->last_y * 0x7FFF / (s->ds->surface->height - 1);
>> +    } else {
>> +        dx = 0;
>> +        dy = 0;
>> +    }
>> +
>> +    kbd_mouse_event(dx, dy, 0, s->button_mask);
>> +
>> +    return TRUE;
>> +}
>> +
>> +static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
>> +{
>> +    int gdk_keycode;
>> +    int qemu_keycode;
>> +
>> +    gdk_keycode = key->hardware_keycode;
>> +
>> +    if (gdk_keycode < 9) {
>> +        qemu_keycode = 0;
>> +    } else if (gdk_keycode < 97) {
>> +        qemu_keycode = gdk_keycode - 8;
>> +    } else if (gdk_keycode < 158) {
>> +        qemu_keycode = translate_evdev_keycode(gdk_keycode - 97);
>> +    } else if (gdk_keycode == 208) { /* Hiragana_Katakana */
>> +        qemu_keycode = 0x70;
>> +    } else if (gdk_keycode == 211) { /* backslash */
>> +        qemu_keycode = 0x73;
>> +    } else {
>> +        qemu_keycode = 0;
>> +    }
>> +
>> +    dprintf("translated GDK keycode %d to QEMU keycode %d (%s)\n",
>> +            gdk_keycode, qemu_keycode,
>> +            (key->type == GDK_KEY_PRESS) ? "down" : "up");
>> +
>> +    if (qemu_keycode & SCANCODE_GREY) {
>> +        kbd_put_keycode(SCANCODE_EMUL0);
>> +    }
>> +
>> +    if (key->type == GDK_KEY_PRESS) {
>> +        kbd_put_keycode(qemu_keycode & SCANCODE_KEYCODEMASK);
>> +    } else if (key->type == GDK_KEY_RELEASE) {
>> +        kbd_put_keycode(qemu_keycode | SCANCODE_UP);
>> +    } else {
>> +        g_assert_not_reached();
>> +    }
>> +
>> +    return TRUE;
>> +}
>> +
>> +/** Window Menu Actions **/
>> +
>> +static void gd_menu_quit(GtkMenuItem *item, void *opaque)
>> +{
>> +    qmp_quit(NULL);
>> +}
>> +
>> +static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque)
>> +{
>> +    GtkDisplayState *s = opaque;
>> +
>> +    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vga_item))) {
>> +        gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), 0);
>> +    }
>> +}
>> +
>> +static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque)
>> +{
>> +    GtkDisplayState *s = opaque;
>> +
>> +    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->show_tabs_item))) {
>> +        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), TRUE);
>> +    } else {
>> +        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
>> +    }
>> +}
>> +
>> +static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
>> +                           gpointer data)
>> +{
>> +    GtkDisplayState *s = data;
>> +
>> +    if (!gtk_widget_get_realized(s->notebook)) {
>> +        return;
>> +    }
>> +
>> +    gd_update_cursor(s, TRUE);
>> +}
>> +
>> +void early_gtk_display_init(void)
>> +{
>> +}
>> +
>> +/** Window Creation **/
>> +
>> +static void gd_connect_signals(GtkDisplayState *s)
>> +{
>> +    g_signal_connect(s->show_tabs_item, "activate",
>> +                     G_CALLBACK(gd_menu_show_tabs), s);
>> +
>> +    g_signal_connect(s->window, "delete-event",
>> +                     G_CALLBACK(gd_window_close), s);
>> +
>> +    g_signal_connect(s->drawing_area, "expose-event",
>> +                     G_CALLBACK(gd_expose_event), s);
>> +    g_signal_connect(s->drawing_area, "motion-notify-event",
>> +                     G_CALLBACK(gd_motion_event), s);
>> +    g_signal_connect(s->drawing_area, "button-press-event",
>> +                     G_CALLBACK(gd_button_event), s);
>> +    g_signal_connect(s->drawing_area, "button-release-event",
>> +                     G_CALLBACK(gd_button_event), s);
>> +    g_signal_connect(s->drawing_area, "key-press-event",
>> +                     G_CALLBACK(gd_key_event), s);
>> +    g_signal_connect(s->drawing_area, "key-release-event",
>> +                     G_CALLBACK(gd_key_event), s);
>> +
>> +    g_signal_connect(s->quit_item, "activate",
>> +                     G_CALLBACK(gd_menu_quit), s);
>> +    g_signal_connect(s->vga_item, "activate",
>> +                     G_CALLBACK(gd_menu_switch_vc), s);
>> +    g_signal_connect(s->notebook, "switch-page",
>> +                     G_CALLBACK(gd_change_page), s);
>> +}
>> +
>> +static void gd_create_menus(GtkDisplayState *s)
>> +{
>> +    GtkStockItem item;
>> +    GtkAccelGroup *accel_group;
>> +    GSList *group = NULL;
>> +    GtkWidget *separator;
>> +
>> +    accel_group = gtk_accel_group_new();
>> +    s->file_menu = gtk_menu_new();
>> +    gtk_menu_set_accel_group(GTK_MENU(s->file_menu), accel_group);
>> +    s->file_menu_item = gtk_menu_item_new_with_mnemonic("_File");
>> +
>> +    s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
>> +    gtk_stock_lookup(GTK_STOCK_QUIT, &item);
>> +    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item),
>> +                                 "<QEMU>/File/Quit");
>> +    gtk_accel_map_add_entry("<QEMU>/File/Quit", item.keyval, item.modifier);
>> +
>> +    s->view_menu = gtk_menu_new();
>> +    gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group);
>> +    s->view_menu_item = gtk_menu_item_new_with_mnemonic("_View");
>> +
>> +    separator = gtk_separator_menu_item_new();
>> +    gtk_menu_append(GTK_MENU(s->view_menu), separator);
>> +
>> +    s->vga_item = gtk_radio_menu_item_new_with_mnemonic(group, "_VGA");
>> +    group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(s->vga_item));
>> +    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->vga_item),
>> +                                 "<QEMU>/View/VGA");
>> +    gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK);
>> +    gtk_menu_append(GTK_MENU(s->view_menu), s->vga_item);
>> +
>> +    separator = gtk_separator_menu_item_new();
>> +    gtk_menu_append(GTK_MENU(s->view_menu), separator);
>> +
>> +    s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic("Show _Tabs");
>> +    gtk_menu_append(GTK_MENU(s->view_menu), s->show_tabs_item);
>> +
>> +    g_object_set_data(G_OBJECT(s->window), "accel_group", accel_group);
>> +    gtk_window_add_accel_group(GTK_WINDOW(s->window), accel_group);
>> +
>> +    gtk_menu_append(GTK_MENU(s->file_menu), s->quit_item);
>> +    gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->file_menu_item), s->file_menu);
>> +    gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->file_menu_item);
>> +
>> +    gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->view_menu_item), s->view_menu);
>> +    gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->view_menu_item);
>> +}
>> +
>> +void gtk_display_init(DisplayState *ds)
>> +{
>> +    GtkDisplayState *s = g_malloc0(sizeof(*s));
>> +
>> +    gtk_init(NULL, NULL);
>> +
>> +    ds->opaque = s;
>> +    s->ds = ds;
>> +    s->dcl.dpy_update = gd_update;
>> +    s->dcl.dpy_resize = gd_resize;
>> +    s->dcl.dpy_refresh = gd_refresh;
>> +    register_displaychangelistener(ds, &s->dcl);
>> +
>> +    s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
>> +    s->vbox = gtk_vbox_new(FALSE, 0);
>> +    s->notebook = gtk_notebook_new();
>> +    s->drawing_area = gtk_drawing_area_new();
>> +    s->menu_bar = gtk_menu_bar_new();
>> +
>> +    s->scale_x = 1.0;
>> +    s->scale_y = 1.0;
>> +
>> +    s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
>> +
>> +    s->mouse_mode_notifier.notify = gd_mouse_mode_change;
>> +    qemu_add_mouse_mode_change_notifier(&s->mouse_mode_notifier);
>> +    qemu_add_vm_change_state_handler(gd_change_runstate, s);
>> +
>> +    gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), s->drawing_area, gtk_label_new("VGA"));
>> +
>> +    gd_create_menus(s);
>> +
>> +    gd_connect_signals(s);
>> +
>> +    gtk_widget_add_events(s->drawing_area,
>> +                          GDK_POINTER_MOTION_MASK |
>> +                          GDK_BUTTON_PRESS_MASK |
>> +                          GDK_BUTTON_RELEASE_MASK |
>> +                          GDK_BUTTON_MOTION_MASK |
>> +                          GDK_SCROLL_MASK |
>> +                          GDK_KEY_PRESS_MASK);
>> +    gtk_widget_set_double_buffered(s->drawing_area, FALSE);
>> +    gtk_widget_set_can_focus(s->drawing_area, TRUE);
>> +
>> +    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
>> +    gtk_notebook_set_show_border(GTK_NOTEBOOK(s->notebook), FALSE);
>> +
>> +    gtk_window_set_resizable(GTK_WINDOW(s->window), FALSE);
>> +
>> +    gd_update_caption(s);
>> +
>> +    gtk_box_pack_start(GTK_BOX(s->vbox), s->menu_bar, FALSE, TRUE, 0);
>> +    gtk_box_pack_start(GTK_BOX(s->vbox), s->notebook, TRUE, TRUE, 0);
>> +
>> +    gtk_container_add(GTK_CONTAINER(s->window), s->vbox);
>> +
>> +    gtk_widget_show_all(s->window);
>> +
>> +    global_state = s;
>> +}
>> --
>> 1.7.5.4
>>
>>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2)
  2012-09-05 20:04   ` Stefan Weil
@ 2012-09-05 20:39     ` Anthony Liguori
  2012-09-05 20:45     ` Jan Kiszka
  1 sibling, 0 replies; 25+ messages in thread
From: Anthony Liguori @ 2012-09-05 20:39 UTC (permalink / raw)
  To: Stefan Weil; +Cc: qemu-devel

Stefan Weil <sw@weilnetz.de> writes:

> Am 05.09.2012 21:18, schrieb Anthony Liguori:
>> This is minimalistic and just contains the basic widget infrastructure.  The GUI
>> consists of a menu and a GtkNotebook.  To start with, the notebook has its tabs
>> hidden which provides a UI that looks very similar to SDL with the exception of
>> the menu bar.
>>
>> The menu bar allows a user to toggle the visibility of the tabs.  Cairo is used
>> for rendering.
>>
>> I used gtk-vnc as a reference.  gtk-vnc solves the same basic problems as QEMU
>> since it was originally written as a remote display for QEMU.  So for the most
>> part, the approach to rendering and keyboard handling should be pretty solid for
>> GTK.
>>
>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
>> ---
>> v1 ->  v2
>>   - add gtk-vnc license
>>   - fix key propagation
>> ---
>>   Makefile         |    2 +
>>   configure        |   25 +++-
>>   console.h        |    4 +
>>   sysemu.h         |    1 +
>>   ui/Makefile.objs |    1 +
>>   ui/gtk.c         |  572 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   6 files changed, 604 insertions(+), 1 deletions(-)
>>   create mode 100644 ui/gtk.c
>>
>
> Hi Anthony,
>
> I tested the previous version of your series and noticed that the
> menu accelerators (especially for file/quit) which are still part of
> this new patch are a bad idea.
>
> Just run a system emulation, start some GUI program in the emulation
> and press Ctrl-Q: you won't terminate the GUI program, but terminate
> QEMU!

How is that different from ctrl-alt-f or any of the other accelerators
we use?

If the argument is that Ctrl-Q is too common, that's one thing, but
we can't avoid using accelerators.

Regards,

Anthony Liguori

>
> Cheers,
>
> Stefan W.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 4/7] gtk: add support for input grabbing (v2)
  2012-09-05 19:37   ` Jan Kiszka
@ 2012-09-05 20:40     ` Anthony Liguori
  2012-09-05 20:43       ` Jan Kiszka
  0 siblings, 1 reply; 25+ messages in thread
From: Anthony Liguori @ 2012-09-05 20:40 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: qemu-devel

Jan Kiszka <jan.kiszka@web.de> writes:

> On 2012-09-05 21:18, Anthony Liguori wrote:
>> There is a small deviation from SDL's behavior here.  Instead of Ctrl+Alt
>> triggering grab, we now use Ctrl-Alt-g to trigger grab.
>> 
>> GTK will not accept Ctrl+Alt as an accelerator since it just consists of
>> modifiers.  Having grab as a proper accelerator is important as it allows a user
>> to override the accelerator for accessibility purposes.
>> 
>> We also are not automatically grabbing on left-click.  Besides the inability to
>> tie mouse clicks to an accelerator, I think this behavior is hard to discover
>> and since it only happens depending on the guest state, it can lead to confusing
>> behavior.
>> 
>> This can be changed in the future if there's a strong resistence to dropping
>> left-click-to-grab, but I think we're better off dropping it.
>> 
>> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
>> ---
>> v1 -> v2
>>  - add a menu option for grab on hover (Jan)
>
> Thanks. Are options like this persistent across VM starts?

No.  I don't want to include that in this series as it opens up a whole
debate about GConf vs. configuration files...

Regards,

Anthony Liguori

>
> Jan

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 4/7] gtk: add support for input grabbing (v2)
  2012-09-05 20:40     ` Anthony Liguori
@ 2012-09-05 20:43       ` Jan Kiszka
  0 siblings, 0 replies; 25+ messages in thread
From: Jan Kiszka @ 2012-09-05 20:43 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1343 bytes --]

On 2012-09-05 22:40, Anthony Liguori wrote:
> Jan Kiszka <jan.kiszka@web.de> writes:
> 
>> On 2012-09-05 21:18, Anthony Liguori wrote:
>>> There is a small deviation from SDL's behavior here.  Instead of Ctrl+Alt
>>> triggering grab, we now use Ctrl-Alt-g to trigger grab.
>>>
>>> GTK will not accept Ctrl+Alt as an accelerator since it just consists of
>>> modifiers.  Having grab as a proper accelerator is important as it allows a user
>>> to override the accelerator for accessibility purposes.
>>>
>>> We also are not automatically grabbing on left-click.  Besides the inability to
>>> tie mouse clicks to an accelerator, I think this behavior is hard to discover
>>> and since it only happens depending on the guest state, it can lead to confusing
>>> behavior.
>>>
>>> This can be changed in the future if there's a strong resistence to dropping
>>> left-click-to-grab, but I think we're better off dropping it.
>>>
>>> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
>>> ---
>>> v1 -> v2
>>>  - add a menu option for grab on hover (Jan)
>>
>> Thanks. Are options like this persistent across VM starts?
> 
> No.  I don't want to include that in this series as it opens up a whole
> debate about GConf vs. configuration files...

Well, but it must be solved. In a later series, that's fine.

Jan



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 259 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2)
  2012-09-05 20:04   ` Stefan Weil
  2012-09-05 20:39     ` Anthony Liguori
@ 2012-09-05 20:45     ` Jan Kiszka
  2012-09-05 22:55       ` Anthony Liguori
  1 sibling, 1 reply; 25+ messages in thread
From: Jan Kiszka @ 2012-09-05 20:45 UTC (permalink / raw)
  To: Stefan Weil; +Cc: Anthony Liguori, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1695 bytes --]

On 2012-09-05 22:04, Stefan Weil wrote:
> Am 05.09.2012 21:18, schrieb Anthony Liguori:
>> This is minimalistic and just contains the basic widget
>> infrastructure.  The GUI
>> consists of a menu and a GtkNotebook.  To start with, the notebook has
>> its tabs
>> hidden which provides a UI that looks very similar to SDL with the
>> exception of
>> the menu bar.
>>
>> The menu bar allows a user to toggle the visibility of the tabs. 
>> Cairo is used
>> for rendering.
>>
>> I used gtk-vnc as a reference.  gtk-vnc solves the same basic problems
>> as QEMU
>> since it was originally written as a remote display for QEMU.  So for
>> the most
>> part, the approach to rendering and keyboard handling should be pretty
>> solid for
>> GTK.
>>
>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
>> ---
>> v1 ->  v2
>>   - add gtk-vnc license
>>   - fix key propagation
>> ---
>>   Makefile         |    2 +
>>   configure        |   25 +++-
>>   console.h        |    4 +
>>   sysemu.h         |    1 +
>>   ui/Makefile.objs |    1 +
>>   ui/gtk.c         |  572
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   6 files changed, 604 insertions(+), 1 deletions(-)
>>   create mode 100644 ui/gtk.c
>>
> 
> Hi Anthony,
> 
> I tested the previous version of your series and noticed that the
> menu accelerators (especially for file/quit) which are still part of
> this new patch are a bad idea.
> 
> Just run a system emulation, start some GUI program in the emulation
> and press Ctrl-Q: you won't terminate the GUI program, but terminate
> QEMU!

Yep, standard accelerators must go, definitely while the input is grabbed.

Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 259 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2)
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2) Anthony Liguori
  2012-09-05 19:53   ` Blue Swirl
  2012-09-05 20:04   ` Stefan Weil
@ 2012-09-05 20:54   ` Jan Kiszka
  2 siblings, 0 replies; 25+ messages in thread
From: Jan Kiszka @ 2012-09-05 20:54 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2041 bytes --]

On 2012-09-05 21:18, Anthony Liguori wrote:
> This is minimalistic and just contains the basic widget infrastructure.  The GUI
> consists of a menu and a GtkNotebook.  To start with, the notebook has its tabs
> hidden which provides a UI that looks very similar to SDL with the exception of
> the menu bar.
> 
> The menu bar allows a user to toggle the visibility of the tabs.  Cairo is used
> for rendering.
> 
> I used gtk-vnc as a reference.  gtk-vnc solves the same basic problems as QEMU
> since it was originally written as a remote display for QEMU.  So for the most
> part, the approach to rendering and keyboard handling should be pretty solid for
> GTK.
> 
> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
> ---
> v1 -> v2
>  - add gtk-vnc license
>  - fix key propagation

...

> +static void gd_create_menus(GtkDisplayState *s)
> +{
> +    GtkStockItem item;
> +    GtkAccelGroup *accel_group;
> +    GSList *group = NULL;
> +    GtkWidget *separator;
> +
> +    accel_group = gtk_accel_group_new();
> +    s->file_menu = gtk_menu_new();
> +    gtk_menu_set_accel_group(GTK_MENU(s->file_menu), accel_group);
> +    s->file_menu_item = gtk_menu_item_new_with_mnemonic("_File");
> +
> +    s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
> +    gtk_stock_lookup(GTK_STOCK_QUIT, &item);
> +    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item),
> +                                 "<QEMU>/File/Quit");
> +    gtk_accel_map_add_entry("<QEMU>/File/Quit", item.keyval, item.modifier);
> +
> +    s->view_menu = gtk_menu_new();
> +    gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group);
> +    s->view_menu_item = gtk_menu_item_new_with_mnemonic("_View");
> +
> +    separator = gtk_separator_menu_item_new();
> +    gtk_menu_append(GTK_MENU(s->view_menu), separator);
> +
> +    s->vga_item = gtk_radio_menu_item_new_with_mnemonic(group, "_VGA");

Minor nit, but "VGA" is the wrong name for QEMU in general. Maybe "Display"?

Jan



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 259 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2)
  2012-09-05 20:38     ` Anthony Liguori
@ 2012-09-05 21:00       ` Blue Swirl
  2012-09-05 23:07         ` Anthony Liguori
  0 siblings, 1 reply; 25+ messages in thread
From: Blue Swirl @ 2012-09-05 21:00 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

On Wed, Sep 5, 2012 at 8:38 PM, Anthony Liguori <aliguori@us.ibm.com> wrote:
> Blue Swirl <blauwirbel@gmail.com> writes:
>
>> On Wed, Sep 5, 2012 at 7:18 PM, Anthony Liguori <aliguori@us.ibm.com> wrote:
>>> This is minimalistic and just contains the basic widget infrastructure.  The GUI
>>> consists of a menu and a GtkNotebook.  To start with, the notebook has its tabs
>>> hidden which provides a UI that looks very similar to SDL with the exception of
>>> the menu bar.
>>>
>>> The menu bar allows a user to toggle the visibility of the tabs.  Cairo is used
>>> for rendering.
>>>
>>> I used gtk-vnc as a reference.  gtk-vnc solves the same basic problems as QEMU
>>> since it was originally written as a remote display for QEMU.  So for the most
>>> part, the approach to rendering and keyboard handling should be pretty solid for
>>> GTK.
>>>
>>> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
>>> ---
>>> v1 -> v2
>>>  - add gtk-vnc license
>>>  - fix key propagation
>>> ---
>>>  Makefile         |    2 +
>>>  configure        |   25 +++-
>>>  console.h        |    4 +
>>>  sysemu.h         |    1 +
>>>  ui/Makefile.objs |    1 +
>>>  ui/gtk.c         |  572 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>  6 files changed, 604 insertions(+), 1 deletions(-)
>>>  create mode 100644 ui/gtk.c
>>>
>>> diff --git a/Makefile b/Makefile
>>> index 1cd5bc8..9523e05 100644
>>> --- a/Makefile
>>> +++ b/Makefile
>>> @@ -122,6 +122,8 @@ ui/cocoa.o: ui/cocoa.m
>>>
>>>  ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o hw/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
>>>
>>> +ui/gtk.o: QEMU_CFLAGS += $(GTK_CFLAGS) $(VTE_CFLAGS)
>>> +
>>>  ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
>>>
>>>  bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
>>> diff --git a/configure b/configure
>>> index d97fd81..586dbd3 100755
>>> --- a/configure
>>> +++ b/configure
>>> @@ -278,7 +278,7 @@ sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
>>>  # default flags for all hosts
>>>  QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
>>>  QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
>>> -QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
>>> +QEMU_CFLAGS="-Wredundant-decls $QEMU_CFLAGS"
>>
>> Is this intentional? I hope not.
>
> I forgot to split this out into a separate patch but yes, this is
> intentional.  GTK won't build with -Wstrict-prototypes.

I think we should avoid this at all costs, for example compile
ui/gtk.c with different set of flags or use
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#pragma GCC diagnostic error "-Wstrict-prototypes"
when the compiler supports them.

>
> Regards,
>
> Anthony Liguori
>
>>
>>>  QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
>>>  QEMU_INCLUDES="-I. -I\$(SRC_PATH) -I\$(SRC_PATH)/fpu"
>>>  if test "$debug_info" = "yes"; then
>>> @@ -1635,6 +1635,23 @@ if test "$sparse" != "no" ; then
>>>  fi
>>>
>>>  ##########################################
>>> +# GTK probe
>>> +
>>> +if test "$gtk" != "no"; then
>>> +    if $pkg_config gtk+-2.0 --modversion >/dev/null 2>/dev/null && \
>>> +       $pkg_config vte --modversion >/dev/null 2>/dev/null; then
>>> +       gtk_cflags=`$pkg_config --cflags gtk+-2.0 2>/dev/null`
>>> +       gtk_libs=`$pkg_config --libs gtk+-2.0 2>/dev/null`
>>> +       vte_cflags=`$pkg_config --cflags vte 2>/dev/null`
>>> +       vte_libs=`$pkg_config --libs vte 2>/dev/null`
>>> +       libs_softmmu="$gtk_libs $vte_libs $libs_softmmu"
>>> +       gtk="yes"
>>> +    else
>>> +       gtk="no"
>>> +    fi
>>> +fi
>>> +
>>> +##########################################
>>>  # SDL probe
>>>
>>>  # Look for sdl configuration program (pkg-config or sdl-config).  Try
>>> @@ -3113,6 +3130,7 @@ if test "$darwin" = "yes" ; then
>>>      echo "Cocoa support     $cocoa"
>>>  fi
>>>  echo "SDL support       $sdl"
>>> +echo "GTK support       $gtk"
>>>  echo "curses support    $curses"
>>>  echo "curl support      $curl"
>>>  echo "mingw32 support   $mingw32"
>>> @@ -3390,6 +3408,11 @@ if test "$bluez" = "yes" ; then
>>>    echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
>>>  fi
>>>  echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
>>> +if test "$gtk" = "yes" ; then
>>> +  echo "CONFIG_GTK=y" >> $config_host_mak
>>> +  echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
>>> +  echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
>>> +fi
>>>  if test "$xen" = "yes" ; then
>>>    echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
>>>    echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
>>> diff --git a/console.h b/console.h
>>> index eb428f9..2bd4814 100644
>>> --- a/console.h
>>> +++ b/console.h
>>> @@ -401,4 +401,8 @@ static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
>>>  /* curses.c */
>>>  void curses_display_init(DisplayState *ds, int full_screen);
>>>
>>> +/* gtk.c */
>>> +void early_gtk_display_init(void);
>>> +void gtk_display_init(DisplayState *ds);
>>> +
>>>  #endif
>>> diff --git a/sysemu.h b/sysemu.h
>>> index 65552ac..09a8523 100644
>>> --- a/sysemu.h
>>> +++ b/sysemu.h
>>> @@ -93,6 +93,7 @@ typedef enum DisplayType
>>>      DT_DEFAULT,
>>>      DT_CURSES,
>>>      DT_SDL,
>>> +    DT_GTK,
>>>      DT_NOGRAPHIC,
>>>      DT_NONE,
>>>  } DisplayType;
>>> diff --git a/ui/Makefile.objs b/ui/Makefile.objs
>>> index adc07be..89f8d64 100644
>>> --- a/ui/Makefile.objs
>>> +++ b/ui/Makefile.objs
>>> @@ -12,3 +12,4 @@ common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
>>>  common-obj-$(CONFIG_COCOA) += cocoa.o
>>>  common-obj-$(CONFIG_CURSES) += curses.o
>>>  common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
>>> +common-obj-$(CONFIG_GTK) += gtk.o
>>> diff --git a/ui/gtk.c b/ui/gtk.c
>>> new file mode 100644
>>> index 0000000..e724956
>>> --- /dev/null
>>> +++ b/ui/gtk.c
>>> @@ -0,0 +1,572 @@
>>> +/*
>>> + * GTK UI
>>> + *
>>> + * Copyright IBM, Corp. 2012
>>> + *
>>> + * Authors:
>>> + *  Anthony Liguori   <aliguori@us.ibm.com>
>>> + *
>>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>>> + * See the COPYING file in the top-level directory.
>>> + *
>>> + * Portions from gtk-vnc:
>>> + *
>>> + * GTK VNC Widget
>>> + *
>>> + * Copyright (C) 2006  Anthony Liguori <anthony@codemonkey.ws>
>>> + * Copyright (C) 2009-2010 Daniel P. Berrange <dan@berrange.com>
>>> + *
>>> + * This library is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU Lesser General Public
>>> + * License as published by the Free Software Foundation; either
>>> + * version 2.0 of the License, or (at your option) any later version.
>>> + *
>>> + * This library 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
>>> + * Lesser General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU Lesser General Public
>>> + * License along with this library; if not, write to the Free Software
>>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
>>
>> Please use the recommended web version like other files.
>>
>>> + */
>>> +
>>> +#include <gtk/gtk.h>
>>> +#include <gdk/gdkkeysyms.h>
>>> +#include <vte/vte.h>
>>> +#include <sys/types.h>
>>> +#include <sys/socket.h>
>>> +#include <sys/un.h>
>>> +#include <sys/wait.h>
>>> +#include <pty.h>
>>> +#include <math.h>
>>> +
>>> +#include "qemu-common.h"
>>> +#include "console.h"
>>> +#include "sysemu.h"
>>> +#include "qmp-commands.h"
>>> +#include "x_keymap.h"
>>> +#include "keymaps.h"
>>> +
>>> +//#define DEBUG_GTK
>>> +
>>> +#ifdef DEBUG_GTK
>>> +#define dprintf(fmt, ...) printf(fmt, ## __VA_ARGS__)
>>
>> dprintf is actually defined by stdio.h. Either rename or #undef first.
>>
>>> +#else
>>> +#define dprintf(fmt, ...) do { } while (0)
>>> +#endif
>>> +
>>> +typedef struct VirtualConsole
>>> +{
>>> +    GtkWidget *menu_item;
>>> +    GtkWidget *terminal;
>>> +    GtkWidget *scrolled_window;
>>> +    CharDriverState *chr;
>>> +    int fd;
>>> +} VirtualConsole;
>>> +
>>> +typedef struct GtkDisplayState
>>> +{
>>> +    GtkWidget *window;
>>> +
>>> +    GtkWidget *menu_bar;
>>> +
>>> +    GtkWidget *file_menu_item;
>>> +    GtkWidget *file_menu;
>>> +    GtkWidget *quit_item;
>>> +
>>> +    GtkWidget *view_menu_item;
>>> +    GtkWidget *view_menu;
>>> +    GtkWidget *vga_item;
>>> +
>>> +    GtkWidget *show_tabs_item;
>>> +
>>> +    GtkWidget *vbox;
>>> +    GtkWidget *notebook;
>>> +    GtkWidget *drawing_area;
>>> +    cairo_surface_t *surface;
>>> +    DisplayChangeListener dcl;
>>> +    DisplayState *ds;
>>> +    int button_mask;
>>> +    int last_x;
>>> +    int last_y;
>>> +
>>> +    double scale_x;
>>> +    double scale_y;
>>> +
>>> +    GdkCursor *null_cursor;
>>> +    Notifier mouse_mode_notifier;
>>> +} GtkDisplayState;
>>> +
>>> +static GtkDisplayState *global_state;
>>> +
>>> +/** Utility Functions **/
>>> +
>>> +static void gd_update_cursor(GtkDisplayState *s, gboolean override)
>>> +{
>>> +    GdkWindow *window;
>>> +    bool on_vga;
>>> +
>>> +    window = gtk_widget_get_window(GTK_WIDGET(s->drawing_area));
>>> +
>>> +    on_vga = (gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0);
>>> +
>>> +    if ((override || on_vga) && kbd_mouse_is_absolute()) {
>>> +        gdk_window_set_cursor(window, s->null_cursor);
>>> +    } else {
>>> +        gdk_window_set_cursor(window, NULL);
>>> +    }
>>> +}
>>> +
>>> +static void gd_update_caption(GtkDisplayState *s)
>>> +{
>>> +    const char *status = "";
>>> +    gchar *title;
>>> +
>>> +    if (!runstate_is_running()) {
>>> +        status = " [Stopped]";
>>> +    }
>>> +
>>> +    if (qemu_name) {
>>> +        title = g_strdup_printf("QEMU (%s)%s", qemu_name, status);
>>> +    } else {
>>> +        title = g_strdup_printf("QEMU%s", status);
>>> +    }
>>> +
>>> +    gtk_window_set_title(GTK_WINDOW(s->window), title);
>>> +
>>> +    g_free(title);
>>> +}
>>> +
>>> +/** DisplayState Callbacks **/
>>> +
>>> +static void gd_update(DisplayState *ds, int x, int y, int w, int h)
>>> +{
>>> +    GtkDisplayState *s = ds->opaque;
>>> +    int x1, x2, y1, y2;
>>> +
>>> +    dprintf("update(x=%d, y=%d, w=%d, h=%d)\n", x, y, w, h);
>>> +
>>> +    x1 = floor(x * s->scale_x);
>>> +    y1 = floor(y * s->scale_y);
>>> +
>>> +    x2 = ceil(x * s->scale_x + w * s->scale_x);
>>> +    y2 = ceil(y * s->scale_y + h * s->scale_y);
>>> +
>>> +    gtk_widget_queue_draw_area(s->drawing_area, x1, y1, (x2 - x1), (y2 - y1));
>>> +}
>>> +
>>> +static void gd_refresh(DisplayState *ds)
>>> +{
>>> +    vga_hw_update();
>>> +}
>>> +
>>> +static void gd_resize(DisplayState *ds)
>>> +{
>>> +    GtkDisplayState *s = ds->opaque;
>>> +    cairo_format_t kind;
>>> +    int stride;
>>> +
>>> +    dprintf("resize(width=%d, height=%d)\n",
>>> +            ds->surface->width, ds->surface->height);
>>> +
>>> +    if (s->surface) {
>>> +        cairo_surface_destroy(s->surface);
>>> +    }
>>> +
>>> +    switch (ds->surface->pf.bits_per_pixel) {
>>> +    case 8:
>>> +        kind = CAIRO_FORMAT_A8;
>>> +        break;
>>> +    case 16:
>>> +        kind = CAIRO_FORMAT_RGB16_565;
>>> +        break;
>>> +    case 32:
>>> +        kind = CAIRO_FORMAT_RGB24;
>>> +        break;
>>> +    default:
>>> +        g_assert_not_reached();
>>> +        break;
>>> +    }
>>> +
>>> +    stride = cairo_format_stride_for_width(kind, ds->surface->width);
>>> +    g_assert_cmpint(ds->surface->linesize, ==, stride);
>>> +
>>> +    s->surface = cairo_image_surface_create_for_data(ds->surface->data,
>>> +                                                     kind,
>>> +                                                     ds->surface->width,
>>> +                                                     ds->surface->height,
>>> +                                                     ds->surface->linesize);
>>> +
>>> +    gtk_widget_set_size_request(s->drawing_area,
>>> +                                ds->surface->width * s->scale_x,
>>> +                                ds->surface->height * s->scale_y);
>>> +}
>>> +
>>> +/** QEMU Events **/
>>> +
>>> +static void gd_change_runstate(void *opaque, int running, RunState state)
>>> +{
>>> +    GtkDisplayState *s = opaque;
>>> +
>>> +    gd_update_caption(s);
>>> +}
>>> +
>>> +static void gd_mouse_mode_change(Notifier *notify, void *data)
>>> +{
>>> +    gd_update_cursor(container_of(notify, GtkDisplayState, mouse_mode_notifier),
>>> +                     FALSE);
>>> +}
>>> +
>>> +/** GTK Events **/
>>> +
>>> +static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
>>> +                                void *opaque)
>>> +{
>>> +    if (!no_quit) {
>>> +        qmp_quit(NULL);
>>> +        return FALSE;
>>> +    }
>>> +
>>> +    return TRUE;
>>> +}
>>> +
>>> +static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
>>> +{
>>> +    GtkDisplayState *s = opaque;
>>> +    int ww, wh;
>>> +    int fbw, fbh;
>>> +
>>> +    fbw = s->ds->surface->width;
>>> +    fbh = s->ds->surface->height;
>>> +
>>> +    gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
>>> +
>>> +    cairo_rectangle(cr, 0, 0, ww, wh);
>>> +
>>> +    if (ww != fbw || wh != fbh) {
>>> +        s->scale_x = (double)ww / fbw;
>>> +        s->scale_y = (double)wh / fbh;
>>> +        cairo_scale(cr, s->scale_x, s->scale_y);
>>> +    } else {
>>> +        s->scale_x = 1.0;
>>> +        s->scale_y = 1.0;
>>> +    }
>>> +
>>> +    cairo_set_source_surface(cr, s->surface, 0, 0);
>>> +    cairo_paint(cr);
>>> +
>>> +    return TRUE;
>>> +}
>>> +
>>> +static gboolean gd_expose_event(GtkWidget *widget, GdkEventExpose *expose,
>>> +                                void *opaque)
>>> +{
>>> +    cairo_t *cr;
>>> +    gboolean ret;
>>> +
>>> +    cr = gdk_cairo_create(gtk_widget_get_window(widget));
>>> +    cairo_rectangle(cr,
>>> +                    expose->area.x,
>>> +                    expose->area.y,
>>> +                    expose->area.width,
>>> +                    expose->area.height);
>>> +    cairo_clip(cr);
>>> +
>>> +    ret = gd_draw_event(widget, cr, opaque);
>>> +
>>> +    cairo_destroy(cr);
>>> +
>>> +    return ret;
>>> +}
>>> +
>>> +static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
>>> +                                void *opaque)
>>> +{
>>> +    GtkDisplayState *s = opaque;
>>> +    int dx, dy;
>>> +    int x, y;
>>> +
>>> +    x = motion->x / s->scale_x;
>>> +    y = motion->y / s->scale_y;
>>> +
>>> +    if (kbd_mouse_is_absolute()) {
>>> +        dx = x * 0x7FFF / (s->ds->surface->width - 1);
>>> +        dy = y * 0x7FFF / (s->ds->surface->height - 1);
>>> +    } else if (s->last_x == -1 || s->last_y == -1) {
>>> +        dx = 0;
>>> +        dy = 0;
>>> +    } else {
>>> +        dx = x - s->last_x;
>>> +        dy = y - s->last_y;
>>> +    }
>>> +
>>> +    s->last_x = x;
>>> +    s->last_y = y;
>>> +
>>> +    if (kbd_mouse_is_absolute()) {
>>> +        kbd_mouse_event(dx, dy, 0, s->button_mask);
>>> +    }
>>> +
>>> +    return TRUE;
>>> +}
>>> +
>>> +static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button,
>>> +                                void *opaque)
>>> +{
>>> +    GtkDisplayState *s = opaque;
>>> +    int dx, dy;
>>> +    int n;
>>> +
>>> +    if (button->button == 1) {
>>> +        n = 0x01;
>>> +    } else if (button->button == 2) {
>>> +        n = 0x04;
>>> +    } else if (button->button == 3) {
>>> +        n = 0x02;
>>> +    } else {
>>> +        n = 0x00;
>>> +    }
>>> +
>>> +    if (button->type == GDK_BUTTON_PRESS) {
>>> +        s->button_mask |= n;
>>> +    } else if (button->type == GDK_BUTTON_RELEASE) {
>>> +        s->button_mask &= ~n;
>>> +    }
>>> +
>>> +    if (kbd_mouse_is_absolute()) {
>>> +        dx = s->last_x * 0x7FFF / (s->ds->surface->width - 1);
>>> +        dy = s->last_y * 0x7FFF / (s->ds->surface->height - 1);
>>> +    } else {
>>> +        dx = 0;
>>> +        dy = 0;
>>> +    }
>>> +
>>> +    kbd_mouse_event(dx, dy, 0, s->button_mask);
>>> +
>>> +    return TRUE;
>>> +}
>>> +
>>> +static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
>>> +{
>>> +    int gdk_keycode;
>>> +    int qemu_keycode;
>>> +
>>> +    gdk_keycode = key->hardware_keycode;
>>> +
>>> +    if (gdk_keycode < 9) {
>>> +        qemu_keycode = 0;
>>> +    } else if (gdk_keycode < 97) {
>>> +        qemu_keycode = gdk_keycode - 8;
>>> +    } else if (gdk_keycode < 158) {
>>> +        qemu_keycode = translate_evdev_keycode(gdk_keycode - 97);
>>> +    } else if (gdk_keycode == 208) { /* Hiragana_Katakana */
>>> +        qemu_keycode = 0x70;
>>> +    } else if (gdk_keycode == 211) { /* backslash */
>>> +        qemu_keycode = 0x73;
>>> +    } else {
>>> +        qemu_keycode = 0;
>>> +    }
>>> +
>>> +    dprintf("translated GDK keycode %d to QEMU keycode %d (%s)\n",
>>> +            gdk_keycode, qemu_keycode,
>>> +            (key->type == GDK_KEY_PRESS) ? "down" : "up");
>>> +
>>> +    if (qemu_keycode & SCANCODE_GREY) {
>>> +        kbd_put_keycode(SCANCODE_EMUL0);
>>> +    }
>>> +
>>> +    if (key->type == GDK_KEY_PRESS) {
>>> +        kbd_put_keycode(qemu_keycode & SCANCODE_KEYCODEMASK);
>>> +    } else if (key->type == GDK_KEY_RELEASE) {
>>> +        kbd_put_keycode(qemu_keycode | SCANCODE_UP);
>>> +    } else {
>>> +        g_assert_not_reached();
>>> +    }
>>> +
>>> +    return TRUE;
>>> +}
>>> +
>>> +/** Window Menu Actions **/
>>> +
>>> +static void gd_menu_quit(GtkMenuItem *item, void *opaque)
>>> +{
>>> +    qmp_quit(NULL);
>>> +}
>>> +
>>> +static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque)
>>> +{
>>> +    GtkDisplayState *s = opaque;
>>> +
>>> +    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vga_item))) {
>>> +        gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), 0);
>>> +    }
>>> +}
>>> +
>>> +static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque)
>>> +{
>>> +    GtkDisplayState *s = opaque;
>>> +
>>> +    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->show_tabs_item))) {
>>> +        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), TRUE);
>>> +    } else {
>>> +        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
>>> +    }
>>> +}
>>> +
>>> +static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
>>> +                           gpointer data)
>>> +{
>>> +    GtkDisplayState *s = data;
>>> +
>>> +    if (!gtk_widget_get_realized(s->notebook)) {
>>> +        return;
>>> +    }
>>> +
>>> +    gd_update_cursor(s, TRUE);
>>> +}
>>> +
>>> +void early_gtk_display_init(void)
>>> +{
>>> +}
>>> +
>>> +/** Window Creation **/
>>> +
>>> +static void gd_connect_signals(GtkDisplayState *s)
>>> +{
>>> +    g_signal_connect(s->show_tabs_item, "activate",
>>> +                     G_CALLBACK(gd_menu_show_tabs), s);
>>> +
>>> +    g_signal_connect(s->window, "delete-event",
>>> +                     G_CALLBACK(gd_window_close), s);
>>> +
>>> +    g_signal_connect(s->drawing_area, "expose-event",
>>> +                     G_CALLBACK(gd_expose_event), s);
>>> +    g_signal_connect(s->drawing_area, "motion-notify-event",
>>> +                     G_CALLBACK(gd_motion_event), s);
>>> +    g_signal_connect(s->drawing_area, "button-press-event",
>>> +                     G_CALLBACK(gd_button_event), s);
>>> +    g_signal_connect(s->drawing_area, "button-release-event",
>>> +                     G_CALLBACK(gd_button_event), s);
>>> +    g_signal_connect(s->drawing_area, "key-press-event",
>>> +                     G_CALLBACK(gd_key_event), s);
>>> +    g_signal_connect(s->drawing_area, "key-release-event",
>>> +                     G_CALLBACK(gd_key_event), s);
>>> +
>>> +    g_signal_connect(s->quit_item, "activate",
>>> +                     G_CALLBACK(gd_menu_quit), s);
>>> +    g_signal_connect(s->vga_item, "activate",
>>> +                     G_CALLBACK(gd_menu_switch_vc), s);
>>> +    g_signal_connect(s->notebook, "switch-page",
>>> +                     G_CALLBACK(gd_change_page), s);
>>> +}
>>> +
>>> +static void gd_create_menus(GtkDisplayState *s)
>>> +{
>>> +    GtkStockItem item;
>>> +    GtkAccelGroup *accel_group;
>>> +    GSList *group = NULL;
>>> +    GtkWidget *separator;
>>> +
>>> +    accel_group = gtk_accel_group_new();
>>> +    s->file_menu = gtk_menu_new();
>>> +    gtk_menu_set_accel_group(GTK_MENU(s->file_menu), accel_group);
>>> +    s->file_menu_item = gtk_menu_item_new_with_mnemonic("_File");
>>> +
>>> +    s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
>>> +    gtk_stock_lookup(GTK_STOCK_QUIT, &item);
>>> +    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item),
>>> +                                 "<QEMU>/File/Quit");
>>> +    gtk_accel_map_add_entry("<QEMU>/File/Quit", item.keyval, item.modifier);
>>> +
>>> +    s->view_menu = gtk_menu_new();
>>> +    gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group);
>>> +    s->view_menu_item = gtk_menu_item_new_with_mnemonic("_View");
>>> +
>>> +    separator = gtk_separator_menu_item_new();
>>> +    gtk_menu_append(GTK_MENU(s->view_menu), separator);
>>> +
>>> +    s->vga_item = gtk_radio_menu_item_new_with_mnemonic(group, "_VGA");
>>> +    group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(s->vga_item));
>>> +    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->vga_item),
>>> +                                 "<QEMU>/View/VGA");
>>> +    gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK);
>>> +    gtk_menu_append(GTK_MENU(s->view_menu), s->vga_item);
>>> +
>>> +    separator = gtk_separator_menu_item_new();
>>> +    gtk_menu_append(GTK_MENU(s->view_menu), separator);
>>> +
>>> +    s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic("Show _Tabs");
>>> +    gtk_menu_append(GTK_MENU(s->view_menu), s->show_tabs_item);
>>> +
>>> +    g_object_set_data(G_OBJECT(s->window), "accel_group", accel_group);
>>> +    gtk_window_add_accel_group(GTK_WINDOW(s->window), accel_group);
>>> +
>>> +    gtk_menu_append(GTK_MENU(s->file_menu), s->quit_item);
>>> +    gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->file_menu_item), s->file_menu);
>>> +    gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->file_menu_item);
>>> +
>>> +    gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->view_menu_item), s->view_menu);
>>> +    gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->view_menu_item);
>>> +}
>>> +
>>> +void gtk_display_init(DisplayState *ds)
>>> +{
>>> +    GtkDisplayState *s = g_malloc0(sizeof(*s));
>>> +
>>> +    gtk_init(NULL, NULL);
>>> +
>>> +    ds->opaque = s;
>>> +    s->ds = ds;
>>> +    s->dcl.dpy_update = gd_update;
>>> +    s->dcl.dpy_resize = gd_resize;
>>> +    s->dcl.dpy_refresh = gd_refresh;
>>> +    register_displaychangelistener(ds, &s->dcl);
>>> +
>>> +    s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
>>> +    s->vbox = gtk_vbox_new(FALSE, 0);
>>> +    s->notebook = gtk_notebook_new();
>>> +    s->drawing_area = gtk_drawing_area_new();
>>> +    s->menu_bar = gtk_menu_bar_new();
>>> +
>>> +    s->scale_x = 1.0;
>>> +    s->scale_y = 1.0;
>>> +
>>> +    s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
>>> +
>>> +    s->mouse_mode_notifier.notify = gd_mouse_mode_change;
>>> +    qemu_add_mouse_mode_change_notifier(&s->mouse_mode_notifier);
>>> +    qemu_add_vm_change_state_handler(gd_change_runstate, s);
>>> +
>>> +    gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), s->drawing_area, gtk_label_new("VGA"));
>>> +
>>> +    gd_create_menus(s);
>>> +
>>> +    gd_connect_signals(s);
>>> +
>>> +    gtk_widget_add_events(s->drawing_area,
>>> +                          GDK_POINTER_MOTION_MASK |
>>> +                          GDK_BUTTON_PRESS_MASK |
>>> +                          GDK_BUTTON_RELEASE_MASK |
>>> +                          GDK_BUTTON_MOTION_MASK |
>>> +                          GDK_SCROLL_MASK |
>>> +                          GDK_KEY_PRESS_MASK);
>>> +    gtk_widget_set_double_buffered(s->drawing_area, FALSE);
>>> +    gtk_widget_set_can_focus(s->drawing_area, TRUE);
>>> +
>>> +    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
>>> +    gtk_notebook_set_show_border(GTK_NOTEBOOK(s->notebook), FALSE);
>>> +
>>> +    gtk_window_set_resizable(GTK_WINDOW(s->window), FALSE);
>>> +
>>> +    gd_update_caption(s);
>>> +
>>> +    gtk_box_pack_start(GTK_BOX(s->vbox), s->menu_bar, FALSE, TRUE, 0);
>>> +    gtk_box_pack_start(GTK_BOX(s->vbox), s->notebook, TRUE, TRUE, 0);
>>> +
>>> +    gtk_container_add(GTK_CONTAINER(s->window), s->vbox);
>>> +
>>> +    gtk_widget_show_all(s->window);
>>> +
>>> +    global_state = s;
>>> +}
>>> --
>>> 1.7.5.4
>>>
>>>
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2)
  2012-09-05 20:45     ` Jan Kiszka
@ 2012-09-05 22:55       ` Anthony Liguori
  0 siblings, 0 replies; 25+ messages in thread
From: Anthony Liguori @ 2012-09-05 22:55 UTC (permalink / raw)
  To: Jan Kiszka, Stefan Weil; +Cc: qemu-devel

Jan Kiszka <jan.kiszka@web.de> writes:

> On 2012-09-05 22:04, Stefan Weil wrote:
>> Am 05.09.2012 21:18, schrieb Anthony Liguori:
>>> This is minimalistic and just contains the basic widget
>>> infrastructure.  The GUI
>>> consists of a menu and a GtkNotebook.  To start with, the notebook has
>>> its tabs
>>> hidden which provides a UI that looks very similar to SDL with the
>>> exception of
>>> the menu bar.
>>>
>>> The menu bar allows a user to toggle the visibility of the tabs. 
>>> Cairo is used
>>> for rendering.
>>>
>>> I used gtk-vnc as a reference.  gtk-vnc solves the same basic problems
>>> as QEMU
>>> since it was originally written as a remote display for QEMU.  So for
>>> the most
>>> part, the approach to rendering and keyboard handling should be pretty
>>> solid for
>>> GTK.
>>>
>>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
>>> ---
>>> v1 ->  v2
>>>   - add gtk-vnc license
>>>   - fix key propagation
>>> ---
>>>   Makefile         |    2 +
>>>   configure        |   25 +++-
>>>   console.h        |    4 +
>>>   sysemu.h         |    1 +
>>>   ui/Makefile.objs |    1 +
>>>   ui/gtk.c         |  572
>>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>   6 files changed, 604 insertions(+), 1 deletions(-)
>>>   create mode 100644 ui/gtk.c
>>>
>> 
>> Hi Anthony,
>> 
>> I tested the previous version of your series and noticed that the
>> menu accelerators (especially for file/quit) which are still part of
>> this new patch are a bad idea.
>> 
>> Just run a system emulation, start some GUI program in the emulation
>> and press Ctrl-Q: you won't terminate the GUI program, but terminate
>> QEMU!
>
> Yep, standard accelerators must go, definitely while the input is
> grabbed.

I finally figured out how to do this in GTK so I can limit the number of
accelerators that are active while keyboard grab is active.

It'll be a part of v4.

Regards,

Anthony Liguori

>
> Jan

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2)
  2012-09-05 21:00       ` Blue Swirl
@ 2012-09-05 23:07         ` Anthony Liguori
  2012-09-08  7:00           ` Blue Swirl
  0 siblings, 1 reply; 25+ messages in thread
From: Anthony Liguori @ 2012-09-05 23:07 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

Blue Swirl <blauwirbel@gmail.com> writes:

> On Wed, Sep 5, 2012 at 8:38 PM, Anthony Liguori <aliguori@us.ibm.com> wrote:
>> Blue Swirl <blauwirbel@gmail.com> writes:
>>
>>> On Wed, Sep 5, 2012 at 7:18 PM, Anthony Liguori <aliguori@us.ibm.com> wrote:
>>>> This is minimalistic and just contains the basic widget infrastructure.  The GUI
>>>> consists of a menu and a GtkNotebook.  To start with, the notebook has its tabs
>>>> hidden which provides a UI that looks very similar to SDL with the exception of
>>>> the menu bar.
>>>>
>>>> The menu bar allows a user to toggle the visibility of the tabs.  Cairo is used
>>>> for rendering.
>>>>
>>>> I used gtk-vnc as a reference.  gtk-vnc solves the same basic problems as QEMU
>>>> since it was originally written as a remote display for QEMU.  So for the most
>>>> part, the approach to rendering and keyboard handling should be pretty solid for
>>>> GTK.
>>>>
>>>> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
>>>> ---
>>>> v1 -> v2
>>>>  - add gtk-vnc license
>>>>  - fix key propagation
>>>> ---
>>>>  Makefile         |    2 +
>>>>  configure        |   25 +++-
>>>>  console.h        |    4 +
>>>>  sysemu.h         |    1 +
>>>>  ui/Makefile.objs |    1 +
>>>>  ui/gtk.c         |  572 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>  6 files changed, 604 insertions(+), 1 deletions(-)
>>>>  create mode 100644 ui/gtk.c
>>>>
>>>> diff --git a/Makefile b/Makefile
>>>> index 1cd5bc8..9523e05 100644
>>>> --- a/Makefile
>>>> +++ b/Makefile
>>>> @@ -122,6 +122,8 @@ ui/cocoa.o: ui/cocoa.m
>>>>
>>>>  ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o hw/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
>>>>
>>>> +ui/gtk.o: QEMU_CFLAGS += $(GTK_CFLAGS) $(VTE_CFLAGS)
>>>> +
>>>>  ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
>>>>
>>>>  bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
>>>> diff --git a/configure b/configure
>>>> index d97fd81..586dbd3 100755
>>>> --- a/configure
>>>> +++ b/configure
>>>> @@ -278,7 +278,7 @@ sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
>>>>  # default flags for all hosts
>>>>  QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
>>>>  QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
>>>> -QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
>>>> +QEMU_CFLAGS="-Wredundant-decls $QEMU_CFLAGS"
>>>
>>> Is this intentional? I hope not.
>>
>> I forgot to split this out into a separate patch but yes, this is
>> intentional.  GTK won't build with -Wstrict-prototypes.
>
> I think we should avoid this at all costs, for example compile
> ui/gtk.c with different set of flags or use
> #pragma GCC diagnostic ignored "-Wstrict-prototypes"
> #pragma GCC diagnostic error "-Wstrict-prototypes"
> when the compiler supports them.

The problem is that anything that includes gtk.h would need this.

I'm not sure I agree this warning has much real value in QEMU.  No one
submits patches using K&R declarations and I think most people are
trained to explicitly use (void).

The problem in GTK is gtkitemfactory.h.  Specifically:

/* We use () here to mean unspecified arguments. This is deprecated
 * as of C99, but we can't change it without breaking compatibility.
 * (Note that if we are included from a C++ program () will mean
 * (void) so an explicit cast will be needed.)
 */
typedef	void	(*GtkItemFactoryCallback)  ();

While deprecated in C99, it's still valid C and it's being used
appropriately.

Note that we require this same construct with getucontext but since it
comes from a system header, it's excluded from warnings like this.

Regards,

Anthony Liguori

>
>>
>> Regards,
>>
>> Anthony Liguori
>>
>>>
>>>>  QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
>>>>  QEMU_INCLUDES="-I. -I\$(SRC_PATH) -I\$(SRC_PATH)/fpu"
>>>>  if test "$debug_info" = "yes"; then
>>>> @@ -1635,6 +1635,23 @@ if test "$sparse" != "no" ; then
>>>>  fi
>>>>
>>>>  ##########################################
>>>> +# GTK probe
>>>> +
>>>> +if test "$gtk" != "no"; then
>>>> +    if $pkg_config gtk+-2.0 --modversion >/dev/null 2>/dev/null && \
>>>> +       $pkg_config vte --modversion >/dev/null 2>/dev/null; then
>>>> +       gtk_cflags=`$pkg_config --cflags gtk+-2.0 2>/dev/null`
>>>> +       gtk_libs=`$pkg_config --libs gtk+-2.0 2>/dev/null`
>>>> +       vte_cflags=`$pkg_config --cflags vte 2>/dev/null`
>>>> +       vte_libs=`$pkg_config --libs vte 2>/dev/null`
>>>> +       libs_softmmu="$gtk_libs $vte_libs $libs_softmmu"
>>>> +       gtk="yes"
>>>> +    else
>>>> +       gtk="no"
>>>> +    fi
>>>> +fi
>>>> +
>>>> +##########################################
>>>>  # SDL probe
>>>>
>>>>  # Look for sdl configuration program (pkg-config or sdl-config).  Try
>>>> @@ -3113,6 +3130,7 @@ if test "$darwin" = "yes" ; then
>>>>      echo "Cocoa support     $cocoa"
>>>>  fi
>>>>  echo "SDL support       $sdl"
>>>> +echo "GTK support       $gtk"
>>>>  echo "curses support    $curses"
>>>>  echo "curl support      $curl"
>>>>  echo "mingw32 support   $mingw32"
>>>> @@ -3390,6 +3408,11 @@ if test "$bluez" = "yes" ; then
>>>>    echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
>>>>  fi
>>>>  echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
>>>> +if test "$gtk" = "yes" ; then
>>>> +  echo "CONFIG_GTK=y" >> $config_host_mak
>>>> +  echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
>>>> +  echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
>>>> +fi
>>>>  if test "$xen" = "yes" ; then
>>>>    echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
>>>>    echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
>>>> diff --git a/console.h b/console.h
>>>> index eb428f9..2bd4814 100644
>>>> --- a/console.h
>>>> +++ b/console.h
>>>> @@ -401,4 +401,8 @@ static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
>>>>  /* curses.c */
>>>>  void curses_display_init(DisplayState *ds, int full_screen);
>>>>
>>>> +/* gtk.c */
>>>> +void early_gtk_display_init(void);
>>>> +void gtk_display_init(DisplayState *ds);
>>>> +
>>>>  #endif
>>>> diff --git a/sysemu.h b/sysemu.h
>>>> index 65552ac..09a8523 100644
>>>> --- a/sysemu.h
>>>> +++ b/sysemu.h
>>>> @@ -93,6 +93,7 @@ typedef enum DisplayType
>>>>      DT_DEFAULT,
>>>>      DT_CURSES,
>>>>      DT_SDL,
>>>> +    DT_GTK,
>>>>      DT_NOGRAPHIC,
>>>>      DT_NONE,
>>>>  } DisplayType;
>>>> diff --git a/ui/Makefile.objs b/ui/Makefile.objs
>>>> index adc07be..89f8d64 100644
>>>> --- a/ui/Makefile.objs
>>>> +++ b/ui/Makefile.objs
>>>> @@ -12,3 +12,4 @@ common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
>>>>  common-obj-$(CONFIG_COCOA) += cocoa.o
>>>>  common-obj-$(CONFIG_CURSES) += curses.o
>>>>  common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
>>>> +common-obj-$(CONFIG_GTK) += gtk.o
>>>> diff --git a/ui/gtk.c b/ui/gtk.c
>>>> new file mode 100644
>>>> index 0000000..e724956
>>>> --- /dev/null
>>>> +++ b/ui/gtk.c
>>>> @@ -0,0 +1,572 @@
>>>> +/*
>>>> + * GTK UI
>>>> + *
>>>> + * Copyright IBM, Corp. 2012
>>>> + *
>>>> + * Authors:
>>>> + *  Anthony Liguori   <aliguori@us.ibm.com>
>>>> + *
>>>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>>>> + * See the COPYING file in the top-level directory.
>>>> + *
>>>> + * Portions from gtk-vnc:
>>>> + *
>>>> + * GTK VNC Widget
>>>> + *
>>>> + * Copyright (C) 2006  Anthony Liguori <anthony@codemonkey.ws>
>>>> + * Copyright (C) 2009-2010 Daniel P. Berrange <dan@berrange.com>
>>>> + *
>>>> + * This library is free software; you can redistribute it and/or
>>>> + * modify it under the terms of the GNU Lesser General Public
>>>> + * License as published by the Free Software Foundation; either
>>>> + * version 2.0 of the License, or (at your option) any later version.
>>>> + *
>>>> + * This library 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
>>>> + * Lesser General Public License for more details.
>>>> + *
>>>> + * You should have received a copy of the GNU Lesser General Public
>>>> + * License along with this library; if not, write to the Free Software
>>>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
>>>
>>> Please use the recommended web version like other files.
>>>
>>>> + */
>>>> +
>>>> +#include <gtk/gtk.h>
>>>> +#include <gdk/gdkkeysyms.h>
>>>> +#include <vte/vte.h>
>>>> +#include <sys/types.h>
>>>> +#include <sys/socket.h>
>>>> +#include <sys/un.h>
>>>> +#include <sys/wait.h>
>>>> +#include <pty.h>
>>>> +#include <math.h>
>>>> +
>>>> +#include "qemu-common.h"
>>>> +#include "console.h"
>>>> +#include "sysemu.h"
>>>> +#include "qmp-commands.h"
>>>> +#include "x_keymap.h"
>>>> +#include "keymaps.h"
>>>> +
>>>> +//#define DEBUG_GTK
>>>> +
>>>> +#ifdef DEBUG_GTK
>>>> +#define dprintf(fmt, ...) printf(fmt, ## __VA_ARGS__)
>>>
>>> dprintf is actually defined by stdio.h. Either rename or #undef first.
>>>
>>>> +#else
>>>> +#define dprintf(fmt, ...) do { } while (0)
>>>> +#endif
>>>> +
>>>> +typedef struct VirtualConsole
>>>> +{
>>>> +    GtkWidget *menu_item;
>>>> +    GtkWidget *terminal;
>>>> +    GtkWidget *scrolled_window;
>>>> +    CharDriverState *chr;
>>>> +    int fd;
>>>> +} VirtualConsole;
>>>> +
>>>> +typedef struct GtkDisplayState
>>>> +{
>>>> +    GtkWidget *window;
>>>> +
>>>> +    GtkWidget *menu_bar;
>>>> +
>>>> +    GtkWidget *file_menu_item;
>>>> +    GtkWidget *file_menu;
>>>> +    GtkWidget *quit_item;
>>>> +
>>>> +    GtkWidget *view_menu_item;
>>>> +    GtkWidget *view_menu;
>>>> +    GtkWidget *vga_item;
>>>> +
>>>> +    GtkWidget *show_tabs_item;
>>>> +
>>>> +    GtkWidget *vbox;
>>>> +    GtkWidget *notebook;
>>>> +    GtkWidget *drawing_area;
>>>> +    cairo_surface_t *surface;
>>>> +    DisplayChangeListener dcl;
>>>> +    DisplayState *ds;
>>>> +    int button_mask;
>>>> +    int last_x;
>>>> +    int last_y;
>>>> +
>>>> +    double scale_x;
>>>> +    double scale_y;
>>>> +
>>>> +    GdkCursor *null_cursor;
>>>> +    Notifier mouse_mode_notifier;
>>>> +} GtkDisplayState;
>>>> +
>>>> +static GtkDisplayState *global_state;
>>>> +
>>>> +/** Utility Functions **/
>>>> +
>>>> +static void gd_update_cursor(GtkDisplayState *s, gboolean override)
>>>> +{
>>>> +    GdkWindow *window;
>>>> +    bool on_vga;
>>>> +
>>>> +    window = gtk_widget_get_window(GTK_WIDGET(s->drawing_area));
>>>> +
>>>> +    on_vga = (gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0);
>>>> +
>>>> +    if ((override || on_vga) && kbd_mouse_is_absolute()) {
>>>> +        gdk_window_set_cursor(window, s->null_cursor);
>>>> +    } else {
>>>> +        gdk_window_set_cursor(window, NULL);
>>>> +    }
>>>> +}
>>>> +
>>>> +static void gd_update_caption(GtkDisplayState *s)
>>>> +{
>>>> +    const char *status = "";
>>>> +    gchar *title;
>>>> +
>>>> +    if (!runstate_is_running()) {
>>>> +        status = " [Stopped]";
>>>> +    }
>>>> +
>>>> +    if (qemu_name) {
>>>> +        title = g_strdup_printf("QEMU (%s)%s", qemu_name, status);
>>>> +    } else {
>>>> +        title = g_strdup_printf("QEMU%s", status);
>>>> +    }
>>>> +
>>>> +    gtk_window_set_title(GTK_WINDOW(s->window), title);
>>>> +
>>>> +    g_free(title);
>>>> +}
>>>> +
>>>> +/** DisplayState Callbacks **/
>>>> +
>>>> +static void gd_update(DisplayState *ds, int x, int y, int w, int h)
>>>> +{
>>>> +    GtkDisplayState *s = ds->opaque;
>>>> +    int x1, x2, y1, y2;
>>>> +
>>>> +    dprintf("update(x=%d, y=%d, w=%d, h=%d)\n", x, y, w, h);
>>>> +
>>>> +    x1 = floor(x * s->scale_x);
>>>> +    y1 = floor(y * s->scale_y);
>>>> +
>>>> +    x2 = ceil(x * s->scale_x + w * s->scale_x);
>>>> +    y2 = ceil(y * s->scale_y + h * s->scale_y);
>>>> +
>>>> +    gtk_widget_queue_draw_area(s->drawing_area, x1, y1, (x2 - x1), (y2 - y1));
>>>> +}
>>>> +
>>>> +static void gd_refresh(DisplayState *ds)
>>>> +{
>>>> +    vga_hw_update();
>>>> +}
>>>> +
>>>> +static void gd_resize(DisplayState *ds)
>>>> +{
>>>> +    GtkDisplayState *s = ds->opaque;
>>>> +    cairo_format_t kind;
>>>> +    int stride;
>>>> +
>>>> +    dprintf("resize(width=%d, height=%d)\n",
>>>> +            ds->surface->width, ds->surface->height);
>>>> +
>>>> +    if (s->surface) {
>>>> +        cairo_surface_destroy(s->surface);
>>>> +    }
>>>> +
>>>> +    switch (ds->surface->pf.bits_per_pixel) {
>>>> +    case 8:
>>>> +        kind = CAIRO_FORMAT_A8;
>>>> +        break;
>>>> +    case 16:
>>>> +        kind = CAIRO_FORMAT_RGB16_565;
>>>> +        break;
>>>> +    case 32:
>>>> +        kind = CAIRO_FORMAT_RGB24;
>>>> +        break;
>>>> +    default:
>>>> +        g_assert_not_reached();
>>>> +        break;
>>>> +    }
>>>> +
>>>> +    stride = cairo_format_stride_for_width(kind, ds->surface->width);
>>>> +    g_assert_cmpint(ds->surface->linesize, ==, stride);
>>>> +
>>>> +    s->surface = cairo_image_surface_create_for_data(ds->surface->data,
>>>> +                                                     kind,
>>>> +                                                     ds->surface->width,
>>>> +                                                     ds->surface->height,
>>>> +                                                     ds->surface->linesize);
>>>> +
>>>> +    gtk_widget_set_size_request(s->drawing_area,
>>>> +                                ds->surface->width * s->scale_x,
>>>> +                                ds->surface->height * s->scale_y);
>>>> +}
>>>> +
>>>> +/** QEMU Events **/
>>>> +
>>>> +static void gd_change_runstate(void *opaque, int running, RunState state)
>>>> +{
>>>> +    GtkDisplayState *s = opaque;
>>>> +
>>>> +    gd_update_caption(s);
>>>> +}
>>>> +
>>>> +static void gd_mouse_mode_change(Notifier *notify, void *data)
>>>> +{
>>>> +    gd_update_cursor(container_of(notify, GtkDisplayState, mouse_mode_notifier),
>>>> +                     FALSE);
>>>> +}
>>>> +
>>>> +/** GTK Events **/
>>>> +
>>>> +static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
>>>> +                                void *opaque)
>>>> +{
>>>> +    if (!no_quit) {
>>>> +        qmp_quit(NULL);
>>>> +        return FALSE;
>>>> +    }
>>>> +
>>>> +    return TRUE;
>>>> +}
>>>> +
>>>> +static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
>>>> +{
>>>> +    GtkDisplayState *s = opaque;
>>>> +    int ww, wh;
>>>> +    int fbw, fbh;
>>>> +
>>>> +    fbw = s->ds->surface->width;
>>>> +    fbh = s->ds->surface->height;
>>>> +
>>>> +    gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
>>>> +
>>>> +    cairo_rectangle(cr, 0, 0, ww, wh);
>>>> +
>>>> +    if (ww != fbw || wh != fbh) {
>>>> +        s->scale_x = (double)ww / fbw;
>>>> +        s->scale_y = (double)wh / fbh;
>>>> +        cairo_scale(cr, s->scale_x, s->scale_y);
>>>> +    } else {
>>>> +        s->scale_x = 1.0;
>>>> +        s->scale_y = 1.0;
>>>> +    }
>>>> +
>>>> +    cairo_set_source_surface(cr, s->surface, 0, 0);
>>>> +    cairo_paint(cr);
>>>> +
>>>> +    return TRUE;
>>>> +}
>>>> +
>>>> +static gboolean gd_expose_event(GtkWidget *widget, GdkEventExpose *expose,
>>>> +                                void *opaque)
>>>> +{
>>>> +    cairo_t *cr;
>>>> +    gboolean ret;
>>>> +
>>>> +    cr = gdk_cairo_create(gtk_widget_get_window(widget));
>>>> +    cairo_rectangle(cr,
>>>> +                    expose->area.x,
>>>> +                    expose->area.y,
>>>> +                    expose->area.width,
>>>> +                    expose->area.height);
>>>> +    cairo_clip(cr);
>>>> +
>>>> +    ret = gd_draw_event(widget, cr, opaque);
>>>> +
>>>> +    cairo_destroy(cr);
>>>> +
>>>> +    return ret;
>>>> +}
>>>> +
>>>> +static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
>>>> +                                void *opaque)
>>>> +{
>>>> +    GtkDisplayState *s = opaque;
>>>> +    int dx, dy;
>>>> +    int x, y;
>>>> +
>>>> +    x = motion->x / s->scale_x;
>>>> +    y = motion->y / s->scale_y;
>>>> +
>>>> +    if (kbd_mouse_is_absolute()) {
>>>> +        dx = x * 0x7FFF / (s->ds->surface->width - 1);
>>>> +        dy = y * 0x7FFF / (s->ds->surface->height - 1);
>>>> +    } else if (s->last_x == -1 || s->last_y == -1) {
>>>> +        dx = 0;
>>>> +        dy = 0;
>>>> +    } else {
>>>> +        dx = x - s->last_x;
>>>> +        dy = y - s->last_y;
>>>> +    }
>>>> +
>>>> +    s->last_x = x;
>>>> +    s->last_y = y;
>>>> +
>>>> +    if (kbd_mouse_is_absolute()) {
>>>> +        kbd_mouse_event(dx, dy, 0, s->button_mask);
>>>> +    }
>>>> +
>>>> +    return TRUE;
>>>> +}
>>>> +
>>>> +static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button,
>>>> +                                void *opaque)
>>>> +{
>>>> +    GtkDisplayState *s = opaque;
>>>> +    int dx, dy;
>>>> +    int n;
>>>> +
>>>> +    if (button->button == 1) {
>>>> +        n = 0x01;
>>>> +    } else if (button->button == 2) {
>>>> +        n = 0x04;
>>>> +    } else if (button->button == 3) {
>>>> +        n = 0x02;
>>>> +    } else {
>>>> +        n = 0x00;
>>>> +    }
>>>> +
>>>> +    if (button->type == GDK_BUTTON_PRESS) {
>>>> +        s->button_mask |= n;
>>>> +    } else if (button->type == GDK_BUTTON_RELEASE) {
>>>> +        s->button_mask &= ~n;
>>>> +    }
>>>> +
>>>> +    if (kbd_mouse_is_absolute()) {
>>>> +        dx = s->last_x * 0x7FFF / (s->ds->surface->width - 1);
>>>> +        dy = s->last_y * 0x7FFF / (s->ds->surface->height - 1);
>>>> +    } else {
>>>> +        dx = 0;
>>>> +        dy = 0;
>>>> +    }
>>>> +
>>>> +    kbd_mouse_event(dx, dy, 0, s->button_mask);
>>>> +
>>>> +    return TRUE;
>>>> +}
>>>> +
>>>> +static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
>>>> +{
>>>> +    int gdk_keycode;
>>>> +    int qemu_keycode;
>>>> +
>>>> +    gdk_keycode = key->hardware_keycode;
>>>> +
>>>> +    if (gdk_keycode < 9) {
>>>> +        qemu_keycode = 0;
>>>> +    } else if (gdk_keycode < 97) {
>>>> +        qemu_keycode = gdk_keycode - 8;
>>>> +    } else if (gdk_keycode < 158) {
>>>> +        qemu_keycode = translate_evdev_keycode(gdk_keycode - 97);
>>>> +    } else if (gdk_keycode == 208) { /* Hiragana_Katakana */
>>>> +        qemu_keycode = 0x70;
>>>> +    } else if (gdk_keycode == 211) { /* backslash */
>>>> +        qemu_keycode = 0x73;
>>>> +    } else {
>>>> +        qemu_keycode = 0;
>>>> +    }
>>>> +
>>>> +    dprintf("translated GDK keycode %d to QEMU keycode %d (%s)\n",
>>>> +            gdk_keycode, qemu_keycode,
>>>> +            (key->type == GDK_KEY_PRESS) ? "down" : "up");
>>>> +
>>>> +    if (qemu_keycode & SCANCODE_GREY) {
>>>> +        kbd_put_keycode(SCANCODE_EMUL0);
>>>> +    }
>>>> +
>>>> +    if (key->type == GDK_KEY_PRESS) {
>>>> +        kbd_put_keycode(qemu_keycode & SCANCODE_KEYCODEMASK);
>>>> +    } else if (key->type == GDK_KEY_RELEASE) {
>>>> +        kbd_put_keycode(qemu_keycode | SCANCODE_UP);
>>>> +    } else {
>>>> +        g_assert_not_reached();
>>>> +    }
>>>> +
>>>> +    return TRUE;
>>>> +}
>>>> +
>>>> +/** Window Menu Actions **/
>>>> +
>>>> +static void gd_menu_quit(GtkMenuItem *item, void *opaque)
>>>> +{
>>>> +    qmp_quit(NULL);
>>>> +}
>>>> +
>>>> +static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque)
>>>> +{
>>>> +    GtkDisplayState *s = opaque;
>>>> +
>>>> +    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vga_item))) {
>>>> +        gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), 0);
>>>> +    }
>>>> +}
>>>> +
>>>> +static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque)
>>>> +{
>>>> +    GtkDisplayState *s = opaque;
>>>> +
>>>> +    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->show_tabs_item))) {
>>>> +        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), TRUE);
>>>> +    } else {
>>>> +        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
>>>> +    }
>>>> +}
>>>> +
>>>> +static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
>>>> +                           gpointer data)
>>>> +{
>>>> +    GtkDisplayState *s = data;
>>>> +
>>>> +    if (!gtk_widget_get_realized(s->notebook)) {
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    gd_update_cursor(s, TRUE);
>>>> +}
>>>> +
>>>> +void early_gtk_display_init(void)
>>>> +{
>>>> +}
>>>> +
>>>> +/** Window Creation **/
>>>> +
>>>> +static void gd_connect_signals(GtkDisplayState *s)
>>>> +{
>>>> +    g_signal_connect(s->show_tabs_item, "activate",
>>>> +                     G_CALLBACK(gd_menu_show_tabs), s);
>>>> +
>>>> +    g_signal_connect(s->window, "delete-event",
>>>> +                     G_CALLBACK(gd_window_close), s);
>>>> +
>>>> +    g_signal_connect(s->drawing_area, "expose-event",
>>>> +                     G_CALLBACK(gd_expose_event), s);
>>>> +    g_signal_connect(s->drawing_area, "motion-notify-event",
>>>> +                     G_CALLBACK(gd_motion_event), s);
>>>> +    g_signal_connect(s->drawing_area, "button-press-event",
>>>> +                     G_CALLBACK(gd_button_event), s);
>>>> +    g_signal_connect(s->drawing_area, "button-release-event",
>>>> +                     G_CALLBACK(gd_button_event), s);
>>>> +    g_signal_connect(s->drawing_area, "key-press-event",
>>>> +                     G_CALLBACK(gd_key_event), s);
>>>> +    g_signal_connect(s->drawing_area, "key-release-event",
>>>> +                     G_CALLBACK(gd_key_event), s);
>>>> +
>>>> +    g_signal_connect(s->quit_item, "activate",
>>>> +                     G_CALLBACK(gd_menu_quit), s);
>>>> +    g_signal_connect(s->vga_item, "activate",
>>>> +                     G_CALLBACK(gd_menu_switch_vc), s);
>>>> +    g_signal_connect(s->notebook, "switch-page",
>>>> +                     G_CALLBACK(gd_change_page), s);
>>>> +}
>>>> +
>>>> +static void gd_create_menus(GtkDisplayState *s)
>>>> +{
>>>> +    GtkStockItem item;
>>>> +    GtkAccelGroup *accel_group;
>>>> +    GSList *group = NULL;
>>>> +    GtkWidget *separator;
>>>> +
>>>> +    accel_group = gtk_accel_group_new();
>>>> +    s->file_menu = gtk_menu_new();
>>>> +    gtk_menu_set_accel_group(GTK_MENU(s->file_menu), accel_group);
>>>> +    s->file_menu_item = gtk_menu_item_new_with_mnemonic("_File");
>>>> +
>>>> +    s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
>>>> +    gtk_stock_lookup(GTK_STOCK_QUIT, &item);
>>>> +    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item),
>>>> +                                 "<QEMU>/File/Quit");
>>>> +    gtk_accel_map_add_entry("<QEMU>/File/Quit", item.keyval, item.modifier);
>>>> +
>>>> +    s->view_menu = gtk_menu_new();
>>>> +    gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group);
>>>> +    s->view_menu_item = gtk_menu_item_new_with_mnemonic("_View");
>>>> +
>>>> +    separator = gtk_separator_menu_item_new();
>>>> +    gtk_menu_append(GTK_MENU(s->view_menu), separator);
>>>> +
>>>> +    s->vga_item = gtk_radio_menu_item_new_with_mnemonic(group, "_VGA");
>>>> +    group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(s->vga_item));
>>>> +    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->vga_item),
>>>> +                                 "<QEMU>/View/VGA");
>>>> +    gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK);
>>>> +    gtk_menu_append(GTK_MENU(s->view_menu), s->vga_item);
>>>> +
>>>> +    separator = gtk_separator_menu_item_new();
>>>> +    gtk_menu_append(GTK_MENU(s->view_menu), separator);
>>>> +
>>>> +    s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic("Show _Tabs");
>>>> +    gtk_menu_append(GTK_MENU(s->view_menu), s->show_tabs_item);
>>>> +
>>>> +    g_object_set_data(G_OBJECT(s->window), "accel_group", accel_group);
>>>> +    gtk_window_add_accel_group(GTK_WINDOW(s->window), accel_group);
>>>> +
>>>> +    gtk_menu_append(GTK_MENU(s->file_menu), s->quit_item);
>>>> +    gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->file_menu_item), s->file_menu);
>>>> +    gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->file_menu_item);
>>>> +
>>>> +    gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->view_menu_item), s->view_menu);
>>>> +    gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->view_menu_item);
>>>> +}
>>>> +
>>>> +void gtk_display_init(DisplayState *ds)
>>>> +{
>>>> +    GtkDisplayState *s = g_malloc0(sizeof(*s));
>>>> +
>>>> +    gtk_init(NULL, NULL);
>>>> +
>>>> +    ds->opaque = s;
>>>> +    s->ds = ds;
>>>> +    s->dcl.dpy_update = gd_update;
>>>> +    s->dcl.dpy_resize = gd_resize;
>>>> +    s->dcl.dpy_refresh = gd_refresh;
>>>> +    register_displaychangelistener(ds, &s->dcl);
>>>> +
>>>> +    s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
>>>> +    s->vbox = gtk_vbox_new(FALSE, 0);
>>>> +    s->notebook = gtk_notebook_new();
>>>> +    s->drawing_area = gtk_drawing_area_new();
>>>> +    s->menu_bar = gtk_menu_bar_new();
>>>> +
>>>> +    s->scale_x = 1.0;
>>>> +    s->scale_y = 1.0;
>>>> +
>>>> +    s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
>>>> +
>>>> +    s->mouse_mode_notifier.notify = gd_mouse_mode_change;
>>>> +    qemu_add_mouse_mode_change_notifier(&s->mouse_mode_notifier);
>>>> +    qemu_add_vm_change_state_handler(gd_change_runstate, s);
>>>> +
>>>> +    gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), s->drawing_area, gtk_label_new("VGA"));
>>>> +
>>>> +    gd_create_menus(s);
>>>> +
>>>> +    gd_connect_signals(s);
>>>> +
>>>> +    gtk_widget_add_events(s->drawing_area,
>>>> +                          GDK_POINTER_MOTION_MASK |
>>>> +                          GDK_BUTTON_PRESS_MASK |
>>>> +                          GDK_BUTTON_RELEASE_MASK |
>>>> +                          GDK_BUTTON_MOTION_MASK |
>>>> +                          GDK_SCROLL_MASK |
>>>> +                          GDK_KEY_PRESS_MASK);
>>>> +    gtk_widget_set_double_buffered(s->drawing_area, FALSE);
>>>> +    gtk_widget_set_can_focus(s->drawing_area, TRUE);
>>>> +
>>>> +    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
>>>> +    gtk_notebook_set_show_border(GTK_NOTEBOOK(s->notebook), FALSE);
>>>> +
>>>> +    gtk_window_set_resizable(GTK_WINDOW(s->window), FALSE);
>>>> +
>>>> +    gd_update_caption(s);
>>>> +
>>>> +    gtk_box_pack_start(GTK_BOX(s->vbox), s->menu_bar, FALSE, TRUE, 0);
>>>> +    gtk_box_pack_start(GTK_BOX(s->vbox), s->notebook, TRUE, TRUE, 0);
>>>> +
>>>> +    gtk_container_add(GTK_CONTAINER(s->window), s->vbox);
>>>> +
>>>> +    gtk_widget_show_all(s->window);
>>>> +
>>>> +    global_state = s;
>>>> +}
>>>> --
>>>> 1.7.5.4
>>>>
>>>>
>>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 6/7] gtk: add translation support
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 6/7] gtk: add translation support Anthony Liguori
@ 2012-09-06 12:18   ` Kevin Wolf
  2012-09-06 12:40     ` Anthony Liguori
  2012-09-06 13:00   ` Peter Maydell
  1 sibling, 1 reply; 25+ messages in thread
From: Kevin Wolf @ 2012-09-06 12:18 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

Am 05.09.2012 21:18, schrieb Anthony Liguori:
> This includes a de_DE translation from Kevin Wolf and an it translation from
> Paolo Bonzini.

Nope, the de_DE one is still your fake translation.

Kevin

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 6/7] gtk: add translation support
  2012-09-06 12:18   ` Kevin Wolf
@ 2012-09-06 12:40     ` Anthony Liguori
  0 siblings, 0 replies; 25+ messages in thread
From: Anthony Liguori @ 2012-09-06 12:40 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel

Kevin Wolf <kwolf@redhat.com> writes:

> Am 05.09.2012 21:18, schrieb Anthony Liguori:
>> This includes a de_DE translation from Kevin Wolf and an it translation from
>> Paolo Bonzini.
>
> Nope, the de_DE one is still your fake translation.

Sorry, I'll fix that in v4.

Regards,

Anthony Liguori

>
> Kevin

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 6/7] gtk: add translation support
  2012-09-05 19:18 ` [Qemu-devel] [PATCH 6/7] gtk: add translation support Anthony Liguori
  2012-09-06 12:18   ` Kevin Wolf
@ 2012-09-06 13:00   ` Peter Maydell
  1 sibling, 0 replies; 25+ messages in thread
From: Peter Maydell @ 2012-09-06 13:00 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

On 5 September 2012 20:18, Anthony Liguori <aliguori@us.ibm.com> wrote:
> --- a/Makefile
> +++ b/Makefile
> @@ -315,6 +315,9 @@ ifneq ($(BLOBS),)
>                 $(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
>         done
>  endif
> +ifeq ($(CONFIG_GTK),y)
> +       $(MAKE) -C po $@ || exit 1
> +endif

The "|| exit 1" is only necessary in cases where we're
running make inside a shell for loop or similar. This
looks like it's just a single simple command, so just
       $(MAKE) -C po $@

should suffice.

-- PMM

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2)
  2012-09-05 23:07         ` Anthony Liguori
@ 2012-09-08  7:00           ` Blue Swirl
  0 siblings, 0 replies; 25+ messages in thread
From: Blue Swirl @ 2012-09-08  7:00 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

On Wed, Sep 5, 2012 at 11:07 PM, Anthony Liguori <aliguori@us.ibm.com> wrote:
> Blue Swirl <blauwirbel@gmail.com> writes:
>
>> On Wed, Sep 5, 2012 at 8:38 PM, Anthony Liguori <aliguori@us.ibm.com> wrote:
>>> Blue Swirl <blauwirbel@gmail.com> writes:
>>>
>>>> On Wed, Sep 5, 2012 at 7:18 PM, Anthony Liguori <aliguori@us.ibm.com> wrote:
>>>>> This is minimalistic and just contains the basic widget infrastructure.  The GUI
>>>>> consists of a menu and a GtkNotebook.  To start with, the notebook has its tabs
>>>>> hidden which provides a UI that looks very similar to SDL with the exception of
>>>>> the menu bar.
>>>>>
>>>>> The menu bar allows a user to toggle the visibility of the tabs.  Cairo is used
>>>>> for rendering.
>>>>>
>>>>> I used gtk-vnc as a reference.  gtk-vnc solves the same basic problems as QEMU
>>>>> since it was originally written as a remote display for QEMU.  So for the most
>>>>> part, the approach to rendering and keyboard handling should be pretty solid for
>>>>> GTK.
>>>>>
>>>>> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
>>>>> ---
>>>>> v1 -> v2
>>>>>  - add gtk-vnc license
>>>>>  - fix key propagation
>>>>> ---
>>>>>  Makefile         |    2 +
>>>>>  configure        |   25 +++-
>>>>>  console.h        |    4 +
>>>>>  sysemu.h         |    1 +
>>>>>  ui/Makefile.objs |    1 +
>>>>>  ui/gtk.c         |  572 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>  6 files changed, 604 insertions(+), 1 deletions(-)
>>>>>  create mode 100644 ui/gtk.c
>>>>>
>>>>> diff --git a/Makefile b/Makefile
>>>>> index 1cd5bc8..9523e05 100644
>>>>> --- a/Makefile
>>>>> +++ b/Makefile
>>>>> @@ -122,6 +122,8 @@ ui/cocoa.o: ui/cocoa.m
>>>>>
>>>>>  ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o hw/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
>>>>>
>>>>> +ui/gtk.o: QEMU_CFLAGS += $(GTK_CFLAGS) $(VTE_CFLAGS)
>>>>> +
>>>>>  ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
>>>>>
>>>>>  bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
>>>>> diff --git a/configure b/configure
>>>>> index d97fd81..586dbd3 100755
>>>>> --- a/configure
>>>>> +++ b/configure
>>>>> @@ -278,7 +278,7 @@ sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
>>>>>  # default flags for all hosts
>>>>>  QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
>>>>>  QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
>>>>> -QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
>>>>> +QEMU_CFLAGS="-Wredundant-decls $QEMU_CFLAGS"
>>>>
>>>> Is this intentional? I hope not.
>>>
>>> I forgot to split this out into a separate patch but yes, this is
>>> intentional.  GTK won't build with -Wstrict-prototypes.
>>
>> I think we should avoid this at all costs, for example compile
>> ui/gtk.c with different set of flags or use
>> #pragma GCC diagnostic ignored "-Wstrict-prototypes"
>> #pragma GCC diagnostic error "-Wstrict-prototypes"
>> when the compiler supports them.
>
> The problem is that anything that includes gtk.h would need this.

But that's only ui/gkt.c.

A nice way to handle this could be to add a check to configure for GTK
compatibility with -Wstrict-prototypes. Then the flag is retained if
either GTK is not used or a fixed GTK appears.

>
> I'm not sure I agree this warning has much real value in QEMU.  No one
> submits patches using K&R declarations and I think most people are
> trained to explicitly use (void).

Right, I had actually confused this with -Wmissing-prototypes, this
flag is not so important. Looking at
a5f1b965dae70f7d41721edaacb109d80721b966, there could be also function
pointer declarations which the flag use may detect but otherwise I
agree.

>
> The problem in GTK is gtkitemfactory.h.  Specifically:
>
> /* We use () here to mean unspecified arguments. This is deprecated
>  * as of C99, but we can't change it without breaking compatibility.
>  * (Note that if we are included from a C++ program () will mean
>  * (void) so an explicit cast will be needed.)
>  */
> typedef void    (*GtkItemFactoryCallback)  ();
>
> While deprecated in C99, it's still valid C and it's being used
> appropriately.
>
> Note that we require this same construct with getucontext but since it
> comes from a system header, it's excluded from warnings like this.

Perhaps the real problem is that GTK is not considered a system header
from compiler point of view. We could use -isystem or #pragma GCC
system_header to fix it:
http://gcc.gnu.org/onlinedocs/cpp/System-Headers.html

The pragmas are not supported by all GCC versions though.

>
> Regards,
>
> Anthony Liguori
>
>>
>>>
>>> Regards,
>>>
>>> Anthony Liguori
>>>
>>>>
>>>>>  QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
>>>>>  QEMU_INCLUDES="-I. -I\$(SRC_PATH) -I\$(SRC_PATH)/fpu"
>>>>>  if test "$debug_info" = "yes"; then
>>>>> @@ -1635,6 +1635,23 @@ if test "$sparse" != "no" ; then
>>>>>  fi
>>>>>
>>>>>  ##########################################
>>>>> +# GTK probe
>>>>> +
>>>>> +if test "$gtk" != "no"; then
>>>>> +    if $pkg_config gtk+-2.0 --modversion >/dev/null 2>/dev/null && \
>>>>> +       $pkg_config vte --modversion >/dev/null 2>/dev/null; then
>>>>> +       gtk_cflags=`$pkg_config --cflags gtk+-2.0 2>/dev/null`
>>>>> +       gtk_libs=`$pkg_config --libs gtk+-2.0 2>/dev/null`
>>>>> +       vte_cflags=`$pkg_config --cflags vte 2>/dev/null`
>>>>> +       vte_libs=`$pkg_config --libs vte 2>/dev/null`
>>>>> +       libs_softmmu="$gtk_libs $vte_libs $libs_softmmu"
>>>>> +       gtk="yes"
>>>>> +    else
>>>>> +       gtk="no"
>>>>> +    fi
>>>>> +fi
>>>>> +
>>>>> +##########################################
>>>>>  # SDL probe
>>>>>
>>>>>  # Look for sdl configuration program (pkg-config or sdl-config).  Try
>>>>> @@ -3113,6 +3130,7 @@ if test "$darwin" = "yes" ; then
>>>>>      echo "Cocoa support     $cocoa"
>>>>>  fi
>>>>>  echo "SDL support       $sdl"
>>>>> +echo "GTK support       $gtk"
>>>>>  echo "curses support    $curses"
>>>>>  echo "curl support      $curl"
>>>>>  echo "mingw32 support   $mingw32"
>>>>> @@ -3390,6 +3408,11 @@ if test "$bluez" = "yes" ; then
>>>>>    echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
>>>>>  fi
>>>>>  echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
>>>>> +if test "$gtk" = "yes" ; then
>>>>> +  echo "CONFIG_GTK=y" >> $config_host_mak
>>>>> +  echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
>>>>> +  echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
>>>>> +fi
>>>>>  if test "$xen" = "yes" ; then
>>>>>    echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
>>>>>    echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
>>>>> diff --git a/console.h b/console.h
>>>>> index eb428f9..2bd4814 100644
>>>>> --- a/console.h
>>>>> +++ b/console.h
>>>>> @@ -401,4 +401,8 @@ static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
>>>>>  /* curses.c */
>>>>>  void curses_display_init(DisplayState *ds, int full_screen);
>>>>>
>>>>> +/* gtk.c */
>>>>> +void early_gtk_display_init(void);
>>>>> +void gtk_display_init(DisplayState *ds);
>>>>> +
>>>>>  #endif
>>>>> diff --git a/sysemu.h b/sysemu.h
>>>>> index 65552ac..09a8523 100644
>>>>> --- a/sysemu.h
>>>>> +++ b/sysemu.h
>>>>> @@ -93,6 +93,7 @@ typedef enum DisplayType
>>>>>      DT_DEFAULT,
>>>>>      DT_CURSES,
>>>>>      DT_SDL,
>>>>> +    DT_GTK,
>>>>>      DT_NOGRAPHIC,
>>>>>      DT_NONE,
>>>>>  } DisplayType;
>>>>> diff --git a/ui/Makefile.objs b/ui/Makefile.objs
>>>>> index adc07be..89f8d64 100644
>>>>> --- a/ui/Makefile.objs
>>>>> +++ b/ui/Makefile.objs
>>>>> @@ -12,3 +12,4 @@ common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
>>>>>  common-obj-$(CONFIG_COCOA) += cocoa.o
>>>>>  common-obj-$(CONFIG_CURSES) += curses.o
>>>>>  common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
>>>>> +common-obj-$(CONFIG_GTK) += gtk.o
>>>>> diff --git a/ui/gtk.c b/ui/gtk.c
>>>>> new file mode 100644
>>>>> index 0000000..e724956
>>>>> --- /dev/null
>>>>> +++ b/ui/gtk.c
>>>>> @@ -0,0 +1,572 @@
>>>>> +/*
>>>>> + * GTK UI
>>>>> + *
>>>>> + * Copyright IBM, Corp. 2012
>>>>> + *
>>>>> + * Authors:
>>>>> + *  Anthony Liguori   <aliguori@us.ibm.com>
>>>>> + *
>>>>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>>>>> + * See the COPYING file in the top-level directory.
>>>>> + *
>>>>> + * Portions from gtk-vnc:
>>>>> + *
>>>>> + * GTK VNC Widget
>>>>> + *
>>>>> + * Copyright (C) 2006  Anthony Liguori <anthony@codemonkey.ws>
>>>>> + * Copyright (C) 2009-2010 Daniel P. Berrange <dan@berrange.com>
>>>>> + *
>>>>> + * This library is free software; you can redistribute it and/or
>>>>> + * modify it under the terms of the GNU Lesser General Public
>>>>> + * License as published by the Free Software Foundation; either
>>>>> + * version 2.0 of the License, or (at your option) any later version.
>>>>> + *
>>>>> + * This library 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
>>>>> + * Lesser General Public License for more details.
>>>>> + *
>>>>> + * You should have received a copy of the GNU Lesser General Public
>>>>> + * License along with this library; if not, write to the Free Software
>>>>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
>>>>
>>>> Please use the recommended web version like other files.
>>>>
>>>>> + */
>>>>> +
>>>>> +#include <gtk/gtk.h>
>>>>> +#include <gdk/gdkkeysyms.h>
>>>>> +#include <vte/vte.h>
>>>>> +#include <sys/types.h>
>>>>> +#include <sys/socket.h>
>>>>> +#include <sys/un.h>
>>>>> +#include <sys/wait.h>
>>>>> +#include <pty.h>
>>>>> +#include <math.h>
>>>>> +
>>>>> +#include "qemu-common.h"
>>>>> +#include "console.h"
>>>>> +#include "sysemu.h"
>>>>> +#include "qmp-commands.h"
>>>>> +#include "x_keymap.h"
>>>>> +#include "keymaps.h"
>>>>> +
>>>>> +//#define DEBUG_GTK
>>>>> +
>>>>> +#ifdef DEBUG_GTK
>>>>> +#define dprintf(fmt, ...) printf(fmt, ## __VA_ARGS__)
>>>>
>>>> dprintf is actually defined by stdio.h. Either rename or #undef first.
>>>>
>>>>> +#else
>>>>> +#define dprintf(fmt, ...) do { } while (0)
>>>>> +#endif
>>>>> +
>>>>> +typedef struct VirtualConsole
>>>>> +{
>>>>> +    GtkWidget *menu_item;
>>>>> +    GtkWidget *terminal;
>>>>> +    GtkWidget *scrolled_window;
>>>>> +    CharDriverState *chr;
>>>>> +    int fd;
>>>>> +} VirtualConsole;
>>>>> +
>>>>> +typedef struct GtkDisplayState
>>>>> +{
>>>>> +    GtkWidget *window;
>>>>> +
>>>>> +    GtkWidget *menu_bar;
>>>>> +
>>>>> +    GtkWidget *file_menu_item;
>>>>> +    GtkWidget *file_menu;
>>>>> +    GtkWidget *quit_item;
>>>>> +
>>>>> +    GtkWidget *view_menu_item;
>>>>> +    GtkWidget *view_menu;
>>>>> +    GtkWidget *vga_item;
>>>>> +
>>>>> +    GtkWidget *show_tabs_item;
>>>>> +
>>>>> +    GtkWidget *vbox;
>>>>> +    GtkWidget *notebook;
>>>>> +    GtkWidget *drawing_area;
>>>>> +    cairo_surface_t *surface;
>>>>> +    DisplayChangeListener dcl;
>>>>> +    DisplayState *ds;
>>>>> +    int button_mask;
>>>>> +    int last_x;
>>>>> +    int last_y;
>>>>> +
>>>>> +    double scale_x;
>>>>> +    double scale_y;
>>>>> +
>>>>> +    GdkCursor *null_cursor;
>>>>> +    Notifier mouse_mode_notifier;
>>>>> +} GtkDisplayState;
>>>>> +
>>>>> +static GtkDisplayState *global_state;
>>>>> +
>>>>> +/** Utility Functions **/
>>>>> +
>>>>> +static void gd_update_cursor(GtkDisplayState *s, gboolean override)
>>>>> +{
>>>>> +    GdkWindow *window;
>>>>> +    bool on_vga;
>>>>> +
>>>>> +    window = gtk_widget_get_window(GTK_WIDGET(s->drawing_area));
>>>>> +
>>>>> +    on_vga = (gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0);
>>>>> +
>>>>> +    if ((override || on_vga) && kbd_mouse_is_absolute()) {
>>>>> +        gdk_window_set_cursor(window, s->null_cursor);
>>>>> +    } else {
>>>>> +        gdk_window_set_cursor(window, NULL);
>>>>> +    }
>>>>> +}
>>>>> +
>>>>> +static void gd_update_caption(GtkDisplayState *s)
>>>>> +{
>>>>> +    const char *status = "";
>>>>> +    gchar *title;
>>>>> +
>>>>> +    if (!runstate_is_running()) {
>>>>> +        status = " [Stopped]";
>>>>> +    }
>>>>> +
>>>>> +    if (qemu_name) {
>>>>> +        title = g_strdup_printf("QEMU (%s)%s", qemu_name, status);
>>>>> +    } else {
>>>>> +        title = g_strdup_printf("QEMU%s", status);
>>>>> +    }
>>>>> +
>>>>> +    gtk_window_set_title(GTK_WINDOW(s->window), title);
>>>>> +
>>>>> +    g_free(title);
>>>>> +}
>>>>> +
>>>>> +/** DisplayState Callbacks **/
>>>>> +
>>>>> +static void gd_update(DisplayState *ds, int x, int y, int w, int h)
>>>>> +{
>>>>> +    GtkDisplayState *s = ds->opaque;
>>>>> +    int x1, x2, y1, y2;
>>>>> +
>>>>> +    dprintf("update(x=%d, y=%d, w=%d, h=%d)\n", x, y, w, h);
>>>>> +
>>>>> +    x1 = floor(x * s->scale_x);
>>>>> +    y1 = floor(y * s->scale_y);
>>>>> +
>>>>> +    x2 = ceil(x * s->scale_x + w * s->scale_x);
>>>>> +    y2 = ceil(y * s->scale_y + h * s->scale_y);
>>>>> +
>>>>> +    gtk_widget_queue_draw_area(s->drawing_area, x1, y1, (x2 - x1), (y2 - y1));
>>>>> +}
>>>>> +
>>>>> +static void gd_refresh(DisplayState *ds)
>>>>> +{
>>>>> +    vga_hw_update();
>>>>> +}
>>>>> +
>>>>> +static void gd_resize(DisplayState *ds)
>>>>> +{
>>>>> +    GtkDisplayState *s = ds->opaque;
>>>>> +    cairo_format_t kind;
>>>>> +    int stride;
>>>>> +
>>>>> +    dprintf("resize(width=%d, height=%d)\n",
>>>>> +            ds->surface->width, ds->surface->height);
>>>>> +
>>>>> +    if (s->surface) {
>>>>> +        cairo_surface_destroy(s->surface);
>>>>> +    }
>>>>> +
>>>>> +    switch (ds->surface->pf.bits_per_pixel) {
>>>>> +    case 8:
>>>>> +        kind = CAIRO_FORMAT_A8;
>>>>> +        break;
>>>>> +    case 16:
>>>>> +        kind = CAIRO_FORMAT_RGB16_565;
>>>>> +        break;
>>>>> +    case 32:
>>>>> +        kind = CAIRO_FORMAT_RGB24;
>>>>> +        break;
>>>>> +    default:
>>>>> +        g_assert_not_reached();
>>>>> +        break;
>>>>> +    }
>>>>> +
>>>>> +    stride = cairo_format_stride_for_width(kind, ds->surface->width);
>>>>> +    g_assert_cmpint(ds->surface->linesize, ==, stride);
>>>>> +
>>>>> +    s->surface = cairo_image_surface_create_for_data(ds->surface->data,
>>>>> +                                                     kind,
>>>>> +                                                     ds->surface->width,
>>>>> +                                                     ds->surface->height,
>>>>> +                                                     ds->surface->linesize);
>>>>> +
>>>>> +    gtk_widget_set_size_request(s->drawing_area,
>>>>> +                                ds->surface->width * s->scale_x,
>>>>> +                                ds->surface->height * s->scale_y);
>>>>> +}
>>>>> +
>>>>> +/** QEMU Events **/
>>>>> +
>>>>> +static void gd_change_runstate(void *opaque, int running, RunState state)
>>>>> +{
>>>>> +    GtkDisplayState *s = opaque;
>>>>> +
>>>>> +    gd_update_caption(s);
>>>>> +}
>>>>> +
>>>>> +static void gd_mouse_mode_change(Notifier *notify, void *data)
>>>>> +{
>>>>> +    gd_update_cursor(container_of(notify, GtkDisplayState, mouse_mode_notifier),
>>>>> +                     FALSE);
>>>>> +}
>>>>> +
>>>>> +/** GTK Events **/
>>>>> +
>>>>> +static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
>>>>> +                                void *opaque)
>>>>> +{
>>>>> +    if (!no_quit) {
>>>>> +        qmp_quit(NULL);
>>>>> +        return FALSE;
>>>>> +    }
>>>>> +
>>>>> +    return TRUE;
>>>>> +}
>>>>> +
>>>>> +static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
>>>>> +{
>>>>> +    GtkDisplayState *s = opaque;
>>>>> +    int ww, wh;
>>>>> +    int fbw, fbh;
>>>>> +
>>>>> +    fbw = s->ds->surface->width;
>>>>> +    fbh = s->ds->surface->height;
>>>>> +
>>>>> +    gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
>>>>> +
>>>>> +    cairo_rectangle(cr, 0, 0, ww, wh);
>>>>> +
>>>>> +    if (ww != fbw || wh != fbh) {
>>>>> +        s->scale_x = (double)ww / fbw;
>>>>> +        s->scale_y = (double)wh / fbh;
>>>>> +        cairo_scale(cr, s->scale_x, s->scale_y);
>>>>> +    } else {
>>>>> +        s->scale_x = 1.0;
>>>>> +        s->scale_y = 1.0;
>>>>> +    }
>>>>> +
>>>>> +    cairo_set_source_surface(cr, s->surface, 0, 0);
>>>>> +    cairo_paint(cr);
>>>>> +
>>>>> +    return TRUE;
>>>>> +}
>>>>> +
>>>>> +static gboolean gd_expose_event(GtkWidget *widget, GdkEventExpose *expose,
>>>>> +                                void *opaque)
>>>>> +{
>>>>> +    cairo_t *cr;
>>>>> +    gboolean ret;
>>>>> +
>>>>> +    cr = gdk_cairo_create(gtk_widget_get_window(widget));
>>>>> +    cairo_rectangle(cr,
>>>>> +                    expose->area.x,
>>>>> +                    expose->area.y,
>>>>> +                    expose->area.width,
>>>>> +                    expose->area.height);
>>>>> +    cairo_clip(cr);
>>>>> +
>>>>> +    ret = gd_draw_event(widget, cr, opaque);
>>>>> +
>>>>> +    cairo_destroy(cr);
>>>>> +
>>>>> +    return ret;
>>>>> +}
>>>>> +
>>>>> +static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
>>>>> +                                void *opaque)
>>>>> +{
>>>>> +    GtkDisplayState *s = opaque;
>>>>> +    int dx, dy;
>>>>> +    int x, y;
>>>>> +
>>>>> +    x = motion->x / s->scale_x;
>>>>> +    y = motion->y / s->scale_y;
>>>>> +
>>>>> +    if (kbd_mouse_is_absolute()) {
>>>>> +        dx = x * 0x7FFF / (s->ds->surface->width - 1);
>>>>> +        dy = y * 0x7FFF / (s->ds->surface->height - 1);
>>>>> +    } else if (s->last_x == -1 || s->last_y == -1) {
>>>>> +        dx = 0;
>>>>> +        dy = 0;
>>>>> +    } else {
>>>>> +        dx = x - s->last_x;
>>>>> +        dy = y - s->last_y;
>>>>> +    }
>>>>> +
>>>>> +    s->last_x = x;
>>>>> +    s->last_y = y;
>>>>> +
>>>>> +    if (kbd_mouse_is_absolute()) {
>>>>> +        kbd_mouse_event(dx, dy, 0, s->button_mask);
>>>>> +    }
>>>>> +
>>>>> +    return TRUE;
>>>>> +}
>>>>> +
>>>>> +static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button,
>>>>> +                                void *opaque)
>>>>> +{
>>>>> +    GtkDisplayState *s = opaque;
>>>>> +    int dx, dy;
>>>>> +    int n;
>>>>> +
>>>>> +    if (button->button == 1) {
>>>>> +        n = 0x01;
>>>>> +    } else if (button->button == 2) {
>>>>> +        n = 0x04;
>>>>> +    } else if (button->button == 3) {
>>>>> +        n = 0x02;
>>>>> +    } else {
>>>>> +        n = 0x00;
>>>>> +    }
>>>>> +
>>>>> +    if (button->type == GDK_BUTTON_PRESS) {
>>>>> +        s->button_mask |= n;
>>>>> +    } else if (button->type == GDK_BUTTON_RELEASE) {
>>>>> +        s->button_mask &= ~n;
>>>>> +    }
>>>>> +
>>>>> +    if (kbd_mouse_is_absolute()) {
>>>>> +        dx = s->last_x * 0x7FFF / (s->ds->surface->width - 1);
>>>>> +        dy = s->last_y * 0x7FFF / (s->ds->surface->height - 1);
>>>>> +    } else {
>>>>> +        dx = 0;
>>>>> +        dy = 0;
>>>>> +    }
>>>>> +
>>>>> +    kbd_mouse_event(dx, dy, 0, s->button_mask);
>>>>> +
>>>>> +    return TRUE;
>>>>> +}
>>>>> +
>>>>> +static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
>>>>> +{
>>>>> +    int gdk_keycode;
>>>>> +    int qemu_keycode;
>>>>> +
>>>>> +    gdk_keycode = key->hardware_keycode;
>>>>> +
>>>>> +    if (gdk_keycode < 9) {
>>>>> +        qemu_keycode = 0;
>>>>> +    } else if (gdk_keycode < 97) {
>>>>> +        qemu_keycode = gdk_keycode - 8;
>>>>> +    } else if (gdk_keycode < 158) {
>>>>> +        qemu_keycode = translate_evdev_keycode(gdk_keycode - 97);
>>>>> +    } else if (gdk_keycode == 208) { /* Hiragana_Katakana */
>>>>> +        qemu_keycode = 0x70;
>>>>> +    } else if (gdk_keycode == 211) { /* backslash */
>>>>> +        qemu_keycode = 0x73;
>>>>> +    } else {
>>>>> +        qemu_keycode = 0;
>>>>> +    }
>>>>> +
>>>>> +    dprintf("translated GDK keycode %d to QEMU keycode %d (%s)\n",
>>>>> +            gdk_keycode, qemu_keycode,
>>>>> +            (key->type == GDK_KEY_PRESS) ? "down" : "up");
>>>>> +
>>>>> +    if (qemu_keycode & SCANCODE_GREY) {
>>>>> +        kbd_put_keycode(SCANCODE_EMUL0);
>>>>> +    }
>>>>> +
>>>>> +    if (key->type == GDK_KEY_PRESS) {
>>>>> +        kbd_put_keycode(qemu_keycode & SCANCODE_KEYCODEMASK);
>>>>> +    } else if (key->type == GDK_KEY_RELEASE) {
>>>>> +        kbd_put_keycode(qemu_keycode | SCANCODE_UP);
>>>>> +    } else {
>>>>> +        g_assert_not_reached();
>>>>> +    }
>>>>> +
>>>>> +    return TRUE;
>>>>> +}
>>>>> +
>>>>> +/** Window Menu Actions **/
>>>>> +
>>>>> +static void gd_menu_quit(GtkMenuItem *item, void *opaque)
>>>>> +{
>>>>> +    qmp_quit(NULL);
>>>>> +}
>>>>> +
>>>>> +static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque)
>>>>> +{
>>>>> +    GtkDisplayState *s = opaque;
>>>>> +
>>>>> +    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vga_item))) {
>>>>> +        gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), 0);
>>>>> +    }
>>>>> +}
>>>>> +
>>>>> +static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque)
>>>>> +{
>>>>> +    GtkDisplayState *s = opaque;
>>>>> +
>>>>> +    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->show_tabs_item))) {
>>>>> +        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), TRUE);
>>>>> +    } else {
>>>>> +        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
>>>>> +    }
>>>>> +}
>>>>> +
>>>>> +static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
>>>>> +                           gpointer data)
>>>>> +{
>>>>> +    GtkDisplayState *s = data;
>>>>> +
>>>>> +    if (!gtk_widget_get_realized(s->notebook)) {
>>>>> +        return;
>>>>> +    }
>>>>> +
>>>>> +    gd_update_cursor(s, TRUE);
>>>>> +}
>>>>> +
>>>>> +void early_gtk_display_init(void)
>>>>> +{
>>>>> +}
>>>>> +
>>>>> +/** Window Creation **/
>>>>> +
>>>>> +static void gd_connect_signals(GtkDisplayState *s)
>>>>> +{
>>>>> +    g_signal_connect(s->show_tabs_item, "activate",
>>>>> +                     G_CALLBACK(gd_menu_show_tabs), s);
>>>>> +
>>>>> +    g_signal_connect(s->window, "delete-event",
>>>>> +                     G_CALLBACK(gd_window_close), s);
>>>>> +
>>>>> +    g_signal_connect(s->drawing_area, "expose-event",
>>>>> +                     G_CALLBACK(gd_expose_event), s);
>>>>> +    g_signal_connect(s->drawing_area, "motion-notify-event",
>>>>> +                     G_CALLBACK(gd_motion_event), s);
>>>>> +    g_signal_connect(s->drawing_area, "button-press-event",
>>>>> +                     G_CALLBACK(gd_button_event), s);
>>>>> +    g_signal_connect(s->drawing_area, "button-release-event",
>>>>> +                     G_CALLBACK(gd_button_event), s);
>>>>> +    g_signal_connect(s->drawing_area, "key-press-event",
>>>>> +                     G_CALLBACK(gd_key_event), s);
>>>>> +    g_signal_connect(s->drawing_area, "key-release-event",
>>>>> +                     G_CALLBACK(gd_key_event), s);
>>>>> +
>>>>> +    g_signal_connect(s->quit_item, "activate",
>>>>> +                     G_CALLBACK(gd_menu_quit), s);
>>>>> +    g_signal_connect(s->vga_item, "activate",
>>>>> +                     G_CALLBACK(gd_menu_switch_vc), s);
>>>>> +    g_signal_connect(s->notebook, "switch-page",
>>>>> +                     G_CALLBACK(gd_change_page), s);
>>>>> +}
>>>>> +
>>>>> +static void gd_create_menus(GtkDisplayState *s)
>>>>> +{
>>>>> +    GtkStockItem item;
>>>>> +    GtkAccelGroup *accel_group;
>>>>> +    GSList *group = NULL;
>>>>> +    GtkWidget *separator;
>>>>> +
>>>>> +    accel_group = gtk_accel_group_new();
>>>>> +    s->file_menu = gtk_menu_new();
>>>>> +    gtk_menu_set_accel_group(GTK_MENU(s->file_menu), accel_group);
>>>>> +    s->file_menu_item = gtk_menu_item_new_with_mnemonic("_File");
>>>>> +
>>>>> +    s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
>>>>> +    gtk_stock_lookup(GTK_STOCK_QUIT, &item);
>>>>> +    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item),
>>>>> +                                 "<QEMU>/File/Quit");
>>>>> +    gtk_accel_map_add_entry("<QEMU>/File/Quit", item.keyval, item.modifier);
>>>>> +
>>>>> +    s->view_menu = gtk_menu_new();
>>>>> +    gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group);
>>>>> +    s->view_menu_item = gtk_menu_item_new_with_mnemonic("_View");
>>>>> +
>>>>> +    separator = gtk_separator_menu_item_new();
>>>>> +    gtk_menu_append(GTK_MENU(s->view_menu), separator);
>>>>> +
>>>>> +    s->vga_item = gtk_radio_menu_item_new_with_mnemonic(group, "_VGA");
>>>>> +    group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(s->vga_item));
>>>>> +    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->vga_item),
>>>>> +                                 "<QEMU>/View/VGA");
>>>>> +    gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK);
>>>>> +    gtk_menu_append(GTK_MENU(s->view_menu), s->vga_item);
>>>>> +
>>>>> +    separator = gtk_separator_menu_item_new();
>>>>> +    gtk_menu_append(GTK_MENU(s->view_menu), separator);
>>>>> +
>>>>> +    s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic("Show _Tabs");
>>>>> +    gtk_menu_append(GTK_MENU(s->view_menu), s->show_tabs_item);
>>>>> +
>>>>> +    g_object_set_data(G_OBJECT(s->window), "accel_group", accel_group);
>>>>> +    gtk_window_add_accel_group(GTK_WINDOW(s->window), accel_group);
>>>>> +
>>>>> +    gtk_menu_append(GTK_MENU(s->file_menu), s->quit_item);
>>>>> +    gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->file_menu_item), s->file_menu);
>>>>> +    gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->file_menu_item);
>>>>> +
>>>>> +    gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->view_menu_item), s->view_menu);
>>>>> +    gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->view_menu_item);
>>>>> +}
>>>>> +
>>>>> +void gtk_display_init(DisplayState *ds)
>>>>> +{
>>>>> +    GtkDisplayState *s = g_malloc0(sizeof(*s));
>>>>> +
>>>>> +    gtk_init(NULL, NULL);
>>>>> +
>>>>> +    ds->opaque = s;
>>>>> +    s->ds = ds;
>>>>> +    s->dcl.dpy_update = gd_update;
>>>>> +    s->dcl.dpy_resize = gd_resize;
>>>>> +    s->dcl.dpy_refresh = gd_refresh;
>>>>> +    register_displaychangelistener(ds, &s->dcl);
>>>>> +
>>>>> +    s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
>>>>> +    s->vbox = gtk_vbox_new(FALSE, 0);
>>>>> +    s->notebook = gtk_notebook_new();
>>>>> +    s->drawing_area = gtk_drawing_area_new();
>>>>> +    s->menu_bar = gtk_menu_bar_new();
>>>>> +
>>>>> +    s->scale_x = 1.0;
>>>>> +    s->scale_y = 1.0;
>>>>> +
>>>>> +    s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
>>>>> +
>>>>> +    s->mouse_mode_notifier.notify = gd_mouse_mode_change;
>>>>> +    qemu_add_mouse_mode_change_notifier(&s->mouse_mode_notifier);
>>>>> +    qemu_add_vm_change_state_handler(gd_change_runstate, s);
>>>>> +
>>>>> +    gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), s->drawing_area, gtk_label_new("VGA"));
>>>>> +
>>>>> +    gd_create_menus(s);
>>>>> +
>>>>> +    gd_connect_signals(s);
>>>>> +
>>>>> +    gtk_widget_add_events(s->drawing_area,
>>>>> +                          GDK_POINTER_MOTION_MASK |
>>>>> +                          GDK_BUTTON_PRESS_MASK |
>>>>> +                          GDK_BUTTON_RELEASE_MASK |
>>>>> +                          GDK_BUTTON_MOTION_MASK |
>>>>> +                          GDK_SCROLL_MASK |
>>>>> +                          GDK_KEY_PRESS_MASK);
>>>>> +    gtk_widget_set_double_buffered(s->drawing_area, FALSE);
>>>>> +    gtk_widget_set_can_focus(s->drawing_area, TRUE);
>>>>> +
>>>>> +    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
>>>>> +    gtk_notebook_set_show_border(GTK_NOTEBOOK(s->notebook), FALSE);
>>>>> +
>>>>> +    gtk_window_set_resizable(GTK_WINDOW(s->window), FALSE);
>>>>> +
>>>>> +    gd_update_caption(s);
>>>>> +
>>>>> +    gtk_box_pack_start(GTK_BOX(s->vbox), s->menu_bar, FALSE, TRUE, 0);
>>>>> +    gtk_box_pack_start(GTK_BOX(s->vbox), s->notebook, TRUE, TRUE, 0);
>>>>> +
>>>>> +    gtk_container_add(GTK_CONTAINER(s->window), s->vbox);
>>>>> +
>>>>> +    gtk_widget_show_all(s->window);
>>>>> +
>>>>> +    global_state = s;
>>>>> +}
>>>>> --
>>>>> 1.7.5.4
>>>>>
>>>>>
>>>
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2012-09-08  7:00 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-05 19:18 [Qemu-devel] [PATCH 0/7] Add GTK UI to enable basic accessibility (v3) Anthony Liguori
2012-09-05 19:18 ` [Qemu-devel] [PATCH 1/7] console: allow VCs to be overridden by UI Anthony Liguori
2012-09-05 19:18 ` [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2) Anthony Liguori
2012-09-05 19:53   ` Blue Swirl
2012-09-05 20:00     ` Eric Blake
2012-09-05 20:38     ` Anthony Liguori
2012-09-05 21:00       ` Blue Swirl
2012-09-05 23:07         ` Anthony Liguori
2012-09-08  7:00           ` Blue Swirl
2012-09-05 20:04   ` Stefan Weil
2012-09-05 20:39     ` Anthony Liguori
2012-09-05 20:45     ` Jan Kiszka
2012-09-05 22:55       ` Anthony Liguori
2012-09-05 20:54   ` Jan Kiszka
2012-09-05 19:18 ` [Qemu-devel] [PATCH 3/7] gtk: add virtual console support (v2) Anthony Liguori
2012-09-05 19:18 ` [Qemu-devel] [PATCH 4/7] gtk: add support for input grabbing (v2) Anthony Liguori
2012-09-05 19:37   ` Jan Kiszka
2012-09-05 20:40     ` Anthony Liguori
2012-09-05 20:43       ` Jan Kiszka
2012-09-05 19:18 ` [Qemu-devel] [PATCH 5/7] gtk: add support for screen scaling and full screen (v3) Anthony Liguori
2012-09-05 19:18 ` [Qemu-devel] [PATCH 6/7] gtk: add translation support Anthony Liguori
2012-09-06 12:18   ` Kevin Wolf
2012-09-06 12:40     ` Anthony Liguori
2012-09-06 13:00   ` Peter Maydell
2012-09-05 19:18 ` [Qemu-devel] [PATCH 7/7] gtk: make default UI (v3) Anthony Liguori

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.