From: Anthony Liguori <aliguori@us.ibm.com>
To: Blue Swirl <blauwirbel@gmail.com>
Cc: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2)
Date: Wed, 05 Sep 2012 18:07:41 -0500 [thread overview]
Message-ID: <87mx14gjb6.fsf@codemonkey.ws> (raw)
In-Reply-To: <CAAu8pHuCYSGYb0jp1QO6AUqUsV4JVYhC4WNrUXAx=cJhR5NhAg@mail.gmail.com>
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
>>>>
>>>>
>>
next prev parent reply other threads:[~2012-09-05 23:07 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87mx14gjb6.fsf@codemonkey.ws \
--to=aliguori@us.ibm.com \
--cc=blauwirbel@gmail.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is 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.