[tip:tools/kvm] kvm tools: Initial GTK+ 3.0 UI

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

 



Commit-ID:  3e6f8fd5d5bd44b00a65485c68c4a4aad3fd1a21
Gitweb:     http://git.kernel.org/tip/3e6f8fd5d5bd44b00a65485c68c4a4aad3fd1a21
Author:     Pekka Enberg <penberg@xxxxxxxxxx>
AuthorDate: Wed, 6 Feb 2013 17:52:57 +0200
Committer:  Pekka Enberg <penberg@xxxxxxxxxx>
CommitDate: Fri, 12 Apr 2013 10:05:31 +0300

kvm tools: Initial GTK+ 3.0 UI

It's barely usable but it isn't getting any better sitting alone in a
private git branch.

You can start a new VM with the GTK UI like this:

  ./vm run --gtk

It's rough around the edges:

- Red and blue color channels are inverted.
- Some keys do not work.
- Mouse does not work.
- GTK assertion failure pops up on shutdown.

but I'm sure there's someone out there that's just dying to improve the
user experience.

Cc: Asias He <asias.hejun@xxxxxxxxx>
Cc: Cyrill Gorcunov <gorcunov@xxxxxxxxxx>
Cc: Ingo Molnar <mingo@xxxxxxxxxx>
Cc: Sasha Levin <levinsasha928@xxxxxxxxx>
Signed-off-by: Pekka Enberg <penberg@xxxxxxxxxx>
---
 tools/kvm/Makefile                 |   9 ++
 tools/kvm/builtin-run.c            |   3 +-
 tools/kvm/config/feature-tests.mak |  11 ++
 tools/kvm/hw/vesa.c                |   2 +-
 tools/kvm/include/kvm/gtk3.h       |  28 ++++
 tools/kvm/include/kvm/kvm-config.h |   1 +
 tools/kvm/ui/{sdl.c => gtk3.c}     | 300 +++++++++++++++++++------------------
 tools/kvm/x86/kvm.c                |   2 +-
 8 files changed, 204 insertions(+), 152 deletions(-)

diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile
index 0c59faa..a0a0a9b 100644
--- a/tools/kvm/Makefile
+++ b/tools/kvm/Makefile
@@ -207,6 +207,15 @@ ifeq ($(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD) -static),y)
 	LIBS_STATOPT	+= -lbfd
 endif
 
+FLAGS_GTK3 := $(CFLAGS) $(shell pkg-config --libs --cflags gtk+-3.0 2>/dev/null)
+ifeq ($(call try-cc,$(SOURCE_GTK3),$(FLAGS_GTK3)),y)
+	OBJS_DYNOPT	+= ui/gtk3.o
+	CFLAGS_DYNOPT	+= -DCONFIG_HAS_GTK3 $(shell pkg-config --cflags gtk+-3.0 2>/dev/null)
+	LIBS_DYNOPT	+= $(shell pkg-config --libs gtk+-3.0 2>/dev/null)
+else
+    $(warning warning GTK3 not found, disables GTK3 support. Please install gtk3-devel or libgtk3.0-dev)
+endif
+
 FLAGS_VNCSERVER := $(CFLAGS) -lvncserver
 ifeq ($(call try-cc,$(SOURCE_VNCSERVER),$(FLAGS_VNCSERVER)),y)
 	OBJS_DYNOPT	+= ui/vnc.o
diff --git a/tools/kvm/builtin-run.c b/tools/kvm/builtin-run.c
index d0b876a..c6f5862 100644
--- a/tools/kvm/builtin-run.c
+++ b/tools/kvm/builtin-run.c
@@ -112,6 +112,7 @@ void kvm_run_set_wrapper_sandbox(void)
 	OPT_BOOLEAN('\0', "balloon", &(cfg)->balloon, "Enable virtio"	\
 			" balloon"),					\
 	OPT_BOOLEAN('\0', "vnc", &(cfg)->vnc, "Enable VNC framebuffer"),\
+	OPT_BOOLEAN('\0', "gtk", &(cfg)->gtk, "Enable GTK framebuffer"),\
 	OPT_BOOLEAN('\0', "sdl", &(cfg)->sdl, "Enable SDL framebuffer"),\
 	OPT_BOOLEAN('\0', "rng", &(cfg)->virtio_rng, "Enable virtio"	\
 			" Random Number Generator"),			\
@@ -604,7 +605,7 @@ static struct kvm *kvm_cmd_run_init(int argc, const char **argv)
                 kvm->cfg.network = DEFAULT_NETWORK;
 
 	memset(real_cmdline, 0, sizeof(real_cmdline));
-	kvm__arch_set_cmdline(real_cmdline, kvm->cfg.vnc || kvm->cfg.sdl);
+	kvm__arch_set_cmdline(real_cmdline, kvm->cfg.vnc || kvm->cfg.sdl || kvm->cfg.gtk);
 
 	if (strlen(real_cmdline) > 0)
 		strcat(real_cmdline, " ");
diff --git a/tools/kvm/config/feature-tests.mak b/tools/kvm/config/feature-tests.mak
index 4a81f56..927ac54 100644
--- a/tools/kvm/config/feature-tests.mak
+++ b/tools/kvm/config/feature-tests.mak
@@ -175,3 +175,14 @@ int main(void)
 	return 0;
 }
 endef
+
+define SOURCE_GTK3
+#include <gtk/gtk.h>
+
+int main(void)
+{
+	gtk_main();
+
+	return 0;
+}
+endef
diff --git a/tools/kvm/hw/vesa.c b/tools/kvm/hw/vesa.c
index 33a675f..47e3a69 100644
--- a/tools/kvm/hw/vesa.c
+++ b/tools/kvm/hw/vesa.c
@@ -59,7 +59,7 @@ struct framebuffer *vesa__init(struct kvm *kvm)
 	char *mem;
 	int r;
 
-	if (!kvm->cfg.vnc && !kvm->cfg.sdl)
+	if (!kvm->cfg.vnc && !kvm->cfg.sdl && !kvm->cfg.gtk)
 		return NULL;
 
 	r = irq__register_device(PCI_DEVICE_ID_VESA, &pin, &line);
diff --git a/tools/kvm/include/kvm/gtk3.h b/tools/kvm/include/kvm/gtk3.h
new file mode 100644
index 0000000..b02dc13
--- /dev/null
+++ b/tools/kvm/include/kvm/gtk3.h
@@ -0,0 +1,28 @@
+#ifndef KVM__GTK3_H
+#define KVM__GTK3_H
+
+#include "kvm/util.h"
+
+struct framebuffer;
+
+#ifdef CONFIG_HAS_GTK3
+int kvm_gtk_init(struct kvm *kvm);
+int kvm_gtk_exit(struct kvm *kvm);
+#else
+static inline int kvm_gtk_init(struct kvm *kvm)
+{
+	if (kvm->cfg.gtk)
+		die("GTK3 support not compiled in. (install the gtk3-devel or libgtk3.0-dev package)");
+
+	return 0;
+}
+static inline int kvm_gtk_exit(struct kvm *kvm)
+{
+	if (kvm->cfg.gtk)
+		die("GTK3 support not compiled in. (install the gtk3-devel or libgtk3.0-dev package)");
+
+	return 0;
+}
+#endif
+
+#endif /* KVM__GTK3_H */
diff --git a/tools/kvm/include/kvm/kvm-config.h b/tools/kvm/include/kvm/kvm-config.h
index c66f481..386fa8c 100644
--- a/tools/kvm/include/kvm/kvm-config.h
+++ b/tools/kvm/include/kvm/kvm-config.h
@@ -48,6 +48,7 @@ struct kvm_config {
 	struct virtio_net_params *net_params;
 	bool single_step;
 	bool vnc;
+	bool gtk;
 	bool sdl;
 	bool balloon;
 	bool using_rootfs;
diff --git a/tools/kvm/ui/sdl.c b/tools/kvm/ui/gtk3.c
similarity index 52%
copy from tools/kvm/ui/sdl.c
copy to tools/kvm/ui/gtk3.c
index a260002..b2335bc 100644
--- a/tools/kvm/ui/sdl.c
+++ b/tools/kvm/ui/gtk3.c
@@ -1,39 +1,37 @@
-#include "kvm/sdl.h"
+#include "kvm/gtk3.h"
 
 #include "kvm/framebuffer.h"
-#include "kvm/i8042.h"
-#include "kvm/util.h"
-#include "kvm/kvm.h"
 #include "kvm/kvm-cpu.h"
+#include "kvm/i8042.h"
 #include "kvm/vesa.h"
+#include "kvm/kvm.h"
 
-#include <SDL/SDL.h>
+#include <gtk/gtk.h>
 #include <pthread.h>
-#include <signal.h>
 #include <linux/err.h>
 
-#define FRAME_RATE		25
+#define FRAME_RATE			25
 
-#define SCANCODE_UNKNOWN      0
-#define SCANCODE_NORMAL       1
-#define SCANCODE_ESCAPED      2
-#define SCANCODE_KEY_PAUSE    3
-#define SCANCODE_KEY_PRNTSCRN 4
+#define SCANCODE_UNKNOWN		0
+#define SCANCODE_NORMAL			1
+#define SCANCODE_ESCAPED		2
+#define SCANCODE_KEY_PAUSE		3
+#define SCANCODE_KEY_PRNTSCRN		4
 
 struct set2_scancode {
 	u8 code;
 	u8 type;
 };
 
-#define DEFINE_SC(_code) {\
-	.code = _code,\
-	.type = SCANCODE_NORMAL,\
+#define DEFINE_SC(_code) {		\
+	.code = _code,			\
+	.type = SCANCODE_NORMAL,	\
 }
 
 /* escaped scancodes */
-#define DEFINE_ESC(_code) {\
-	.code = _code,\
-	.type = SCANCODE_ESCAPED,\
+#define DEFINE_ESC(_code) {		\
+	.code = _code,			\
+	.type = SCANCODE_ESCAPED,	\
 }
 
 static const struct set2_scancode const keymap[256] = {
@@ -139,169 +137,172 @@ static const struct set2_scancode const keymap[256] = {
 	[118]	= DEFINE_ESC(0x70),	/* <ins> */
 	[119]	= DEFINE_ESC(0x71),	/* <delete> */
 };
-static bool running, done;
+
+static cairo_surface_t	*surface;
+static bool		done;
 
 static const struct set2_scancode *to_code(u8 scancode)
 {
-	return &keymap[scancode];
+        return &keymap[scancode];
 }
 
-static void key_press(const struct set2_scancode *sc)
+static gboolean
+kvm_gtk_configure_event(GtkWidget * widget, GdkEventConfigure * event, gpointer data)
 {
-	switch (sc->type) {
-	case SCANCODE_ESCAPED:
-		kbd_queue(0xe0);
-		/* fallthrough */
-	case SCANCODE_NORMAL:
-		kbd_queue(sc->code);
-		break;
-	case SCANCODE_KEY_PAUSE:
-		kbd_queue(0xe1);
-		kbd_queue(0x14);
-		kbd_queue(0x77);
-		kbd_queue(0xe1);
-		kbd_queue(0xf0);
-		kbd_queue(0x14);
-		kbd_queue(0x77);
-		break;
-	case SCANCODE_KEY_PRNTSCRN:
-		kbd_queue(0xe0);
-		kbd_queue(0x12);
-		kbd_queue(0xe0);
-		kbd_queue(0x7c);
-		break;
-	}
+	struct framebuffer *fb = data;
+	int stride;
+
+	if (surface)
+		cairo_surface_destroy(surface);
+
+	stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, fb->width);
+
+	surface =
+	    cairo_image_surface_create_for_data((void *) fb->mem,
+						CAIRO_FORMAT_RGB24,
+						fb->width,
+						fb->height,
+						stride);
+
+	return TRUE;
 }
 
-static void key_release(const struct set2_scancode *sc)
+static gboolean kvm_gtk_draw(GtkWidget *widget, cairo_t *cr, gpointer data)
 {
-	switch (sc->type) {
-	case SCANCODE_ESCAPED:
-		kbd_queue(0xe0);
-		/* fallthrough */
-	case SCANCODE_NORMAL:
-		kbd_queue(0xf0);
-		kbd_queue(sc->code);
-		break;
-	case SCANCODE_KEY_PAUSE:
-		/* nothing to do */
-		break;
-	case SCANCODE_KEY_PRNTSCRN:
-		kbd_queue(0xe0);
-		kbd_queue(0xf0);
-		kbd_queue(0x7c);
-		kbd_queue(0xe0);
-		kbd_queue(0xf0);
-		kbd_queue(0x12);
-		break;
-	}
+	cairo_set_source_surface(cr, surface, 0, 0);
+
+	cairo_paint(cr);
+
+	return FALSE;
+}
+
+static void kvm_gtk_destroy(void)
+{
+	if (surface)
+		cairo_surface_destroy(surface);
+
+	gtk_main_quit();
 }
 
-static void *sdl__thread(void *p)
+static gboolean kvm_gtk_redraw(GtkWidget * window)
+{
+	gtk_widget_queue_draw(window);
+
+	return TRUE;
+}
+
+static gboolean
+kvm_gtk_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
+{
+	const struct set2_scancode *sc = to_code(event->hardware_keycode);
+
+        switch (sc->type) {
+        case SCANCODE_ESCAPED:
+                kbd_queue(0xe0);
+                /* fallthrough */
+        case SCANCODE_NORMAL:
+                kbd_queue(sc->code);
+                break;
+        case SCANCODE_KEY_PAUSE:
+                kbd_queue(0xe1);
+                kbd_queue(0x14);
+                kbd_queue(0x77);
+                kbd_queue(0xe1);
+                kbd_queue(0xf0);
+                kbd_queue(0x14);
+                kbd_queue(0x77);
+                break;
+        case SCANCODE_KEY_PRNTSCRN:
+                kbd_queue(0xe0);
+                kbd_queue(0x12);
+                kbd_queue(0xe0);
+                kbd_queue(0x7c);
+                break;
+        }
+
+	return TRUE;
+}
+
+static void *kvm_gtk_thread(void *p)
 {
-	Uint32 rmask, gmask, bmask, amask;
 	struct framebuffer *fb = p;
-	SDL_Surface *guest_screen;
-	SDL_Surface *screen;
-	SDL_Event ev;
-	Uint32 flags;
-
-	kvm__set_thread_name("kvm-sdl-worker");
-
-	if (SDL_Init(SDL_INIT_VIDEO) != 0)
-		die("Unable to initialize SDL");
-
-	rmask = 0x000000ff;
-	gmask = 0x0000ff00;
-	bmask = 0x00ff0000;
-	amask = 0x00000000;
-
-	guest_screen = SDL_CreateRGBSurfaceFrom(fb->mem, fb->width, fb->height, fb->depth, fb->width * fb->depth / 8, rmask, gmask, bmask, amask);
-	if (!guest_screen)
-		die("Unable to create SDL RBG surface");
-
-	flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_DOUBLEBUF;
-
-	SDL_WM_SetCaption("KVM tool", "KVM tool");
-
-	screen = SDL_SetVideoMode(fb->width, fb->height, fb->depth, flags);
-	if (!screen)
-		die("Unable to set SDL video mode");
-
-	SDL_EnableKeyRepeat(200, 50);
-
-	while (running) {
-		SDL_BlitSurface(guest_screen, NULL, screen, NULL);
-		SDL_Flip(screen);
-
-		while (SDL_PollEvent(&ev)) {
-			switch (ev.type) {
-			case SDL_KEYDOWN: {
-				const struct set2_scancode *sc = to_code(ev.key.keysym.scancode);
-				if (sc->type == SCANCODE_UNKNOWN) {
-					pr_warning("key '%d' not found in keymap", ev.key.keysym.scancode);
-					break;
-				}
-				key_press(sc);
-				break;
-			}
-			case SDL_KEYUP: {
-				const struct set2_scancode *sc = to_code(ev.key.keysym.scancode);
-				if (sc->type == SCANCODE_UNKNOWN)
-					break;
-				key_release(sc);
-				break;
-			}
-			case SDL_QUIT:
-				goto exit;
-			}
-		}
-
-		SDL_Delay(1000 / FRAME_RATE);
-	}
+	GtkWidget *window;
+	GtkWidget *frame;
+	GtkWidget *da;
+
+	gtk_init(NULL, NULL);
+
+	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+	gtk_window_set_title(GTK_WINDOW(window), "VM");
+
+	g_signal_connect(window, "destroy", G_CALLBACK(kvm_gtk_destroy), NULL);
+
+	gtk_container_set_border_width(GTK_CONTAINER(window), 8);
+
+	frame = gtk_frame_new(NULL);
+
+	gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
+	gtk_container_add(GTK_CONTAINER(window), frame);
+
+	da = gtk_drawing_area_new();
+
+	gtk_widget_set_size_request(da, 100, 100);
+
+	gtk_container_add(GTK_CONTAINER(frame), da);
+
+	g_signal_connect(da, "draw", G_CALLBACK(kvm_gtk_draw), NULL);
+	g_signal_connect(da, "configure-event",
+			 G_CALLBACK(kvm_gtk_configure_event), fb);
+	g_signal_connect(G_OBJECT (window), "key_press_event", G_CALLBACK(kvm_gtk_key_press), NULL);
+
+
+	gtk_widget_set_events(da, gtk_widget_get_events(da)
+			      | GDK_BUTTON_PRESS_MASK
+			      | GDK_POINTER_MOTION_MASK
+			      | GDK_POINTER_MOTION_HINT_MASK);
+
+	gtk_widget_show_all(window);
+
+	g_timeout_add(1000 / FRAME_RATE, (GSourceFunc) kvm_gtk_redraw, window);
+
+	gtk_main();
 
-	if (running == false && done == false) {
-		done = true;
-		return NULL;
-	}
-exit:
 	done = true;
-	kvm_cpu__reboot(fb->kvm);
 
 	return NULL;
 }
 
-static int sdl__start(struct framebuffer *fb)
+static int kvm_gtk_start(struct framebuffer *fb)
 {
 	pthread_t thread;
 
-	running = true;
-
-	if (pthread_create(&thread, NULL, sdl__thread, fb) != 0)
+	if (pthread_create(&thread, NULL, kvm_gtk_thread, fb) != 0)
 		return -1;
 
 	return 0;
 }
 
-static int sdl__stop(struct framebuffer *fb)
+static int kvm_gtk_stop(struct framebuffer *fb)
 {
-	running = false;
-	while (done == false)
+	gtk_main_quit();
+
+	while (!done)
 		sleep(0);
 
 	return 0;
 }
 
-static struct fb_target_operations sdl_ops = {
-	.start	= sdl__start,
-	.stop	= sdl__stop,
+static struct fb_target_operations kvm_gtk_ops = {
+	.start		= kvm_gtk_start,
+	.stop		= kvm_gtk_stop,
 };
 
-int sdl__init(struct kvm *kvm)
+int kvm_gtk_init(struct kvm *kvm)
 {
 	struct framebuffer *fb;
 
-	if (!kvm->cfg.sdl)
+	if (!kvm->cfg.gtk)
 		return 0;
 
 	fb = vesa__init(kvm);
@@ -310,15 +311,16 @@ int sdl__init(struct kvm *kvm)
 		return PTR_ERR(fb);
 	}
 
-	return fb__attach(fb, &sdl_ops);
+	return fb__attach(fb, &kvm_gtk_ops);
 }
-dev_init(sdl__init);
 
-int sdl__exit(struct kvm *kvm)
+int kvm_gtk_exit(struct kvm *kvm)
 {
-	if (kvm->cfg.sdl)
-		return sdl__stop(NULL);
+	if (kvm->cfg.gtk)
+		return kvm_gtk_stop(NULL);
 
 	return 0;
 }
-dev_exit(sdl__exit);
+
+dev_init(kvm_gtk_init);
+dev_exit(kvm_gtk_exit);
diff --git a/tools/kvm/x86/kvm.c b/tools/kvm/x86/kvm.c
index 2ba1db0..9b46772 100644
--- a/tools/kvm/x86/kvm.c
+++ b/tools/kvm/x86/kvm.c
@@ -296,7 +296,7 @@ bool load_bzimage(struct kvm *kvm, int fd_kernel, int fd_initrd,
 
 
 	/* vidmode should be either specified or set by default */
-	if (kvm->cfg.vnc || kvm->cfg.sdl) {
+	if (kvm->cfg.vnc || kvm->cfg.sdl || kvm->cfg.gtk) {
 		if (!kvm->cfg.arch.vidmode)
 			vidmode = 0x312;
 		else
--
To unsubscribe from this list: send the line "unsubscribe linux-tip-commits" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Stable Commits]     [Linux Stable Kernel]     [Linux Kernel]     [Linux USB Devel]     [Linux Video &Media]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux