mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-06-16 02:15:47 +00:00
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@gmail.com> Cc: Cyrill Gorcunov <gorcunov@openvz.org> Cc: Ingo Molnar <mingo@kernel.org> Cc: Sasha Levin <levinsasha928@gmail.com> Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
committed by
Will Deacon
parent
61ebda7762
commit
7bcceb95fd
@@ -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
|
||||
|
||||
+2
-1
@@ -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, " ");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,326 @@
|
||||
#include "kvm/gtk3.h"
|
||||
|
||||
#include "kvm/framebuffer.h"
|
||||
#include "kvm/kvm-cpu.h"
|
||||
#include "kvm/i8042.h"
|
||||
#include "kvm/vesa.h"
|
||||
#include "kvm/kvm.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <pthread.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#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
|
||||
|
||||
struct set2_scancode {
|
||||
u8 code;
|
||||
u8 type;
|
||||
};
|
||||
|
||||
#define DEFINE_SC(_code) { \
|
||||
.code = _code, \
|
||||
.type = SCANCODE_NORMAL, \
|
||||
}
|
||||
|
||||
/* escaped scancodes */
|
||||
#define DEFINE_ESC(_code) { \
|
||||
.code = _code, \
|
||||
.type = SCANCODE_ESCAPED, \
|
||||
}
|
||||
|
||||
static const struct set2_scancode const keymap[256] = {
|
||||
[9] = DEFINE_SC(0x76), /* <esc> */
|
||||
[10] = DEFINE_SC(0x16), /* 1 */
|
||||
[11] = DEFINE_SC(0x1e), /* 2 */
|
||||
[12] = DEFINE_SC(0x26), /* 3 */
|
||||
[13] = DEFINE_SC(0x25), /* 4 */
|
||||
[14] = DEFINE_SC(0x2e), /* 5 */
|
||||
[15] = DEFINE_SC(0x36), /* 6 */
|
||||
[16] = DEFINE_SC(0x3d), /* 7 */
|
||||
[17] = DEFINE_SC(0x3e), /* 8 */
|
||||
[18] = DEFINE_SC(0x46), /* 9 */
|
||||
[19] = DEFINE_SC(0x45), /* 9 */
|
||||
[20] = DEFINE_SC(0x4e), /* - */
|
||||
[21] = DEFINE_SC(0x55), /* + */
|
||||
[22] = DEFINE_SC(0x66), /* <backspace> */
|
||||
[23] = DEFINE_SC(0x0d), /* <tab> */
|
||||
[24] = DEFINE_SC(0x15), /* q */
|
||||
[25] = DEFINE_SC(0x1d), /* w */
|
||||
[26] = DEFINE_SC(0x24), /* e */
|
||||
[27] = DEFINE_SC(0x2d), /* r */
|
||||
[28] = DEFINE_SC(0x2c), /* t */
|
||||
[29] = DEFINE_SC(0x35), /* y */
|
||||
[30] = DEFINE_SC(0x3c), /* u */
|
||||
[31] = DEFINE_SC(0x43), /* i */
|
||||
[32] = DEFINE_SC(0x44), /* o */
|
||||
[33] = DEFINE_SC(0x4d), /* p */
|
||||
[34] = DEFINE_SC(0x54), /* [ */
|
||||
[35] = DEFINE_SC(0x5b), /* ] */
|
||||
[36] = DEFINE_SC(0x5a), /* <enter> */
|
||||
[37] = DEFINE_SC(0x14), /* <left ctrl> */
|
||||
[38] = DEFINE_SC(0x1c), /* a */
|
||||
[39] = DEFINE_SC(0x1b), /* s */
|
||||
[40] = DEFINE_SC(0x23), /* d */
|
||||
[41] = DEFINE_SC(0x2b), /* f */
|
||||
[42] = DEFINE_SC(0x34), /* g */
|
||||
[43] = DEFINE_SC(0x33), /* h */
|
||||
[44] = DEFINE_SC(0x3b), /* j */
|
||||
[45] = DEFINE_SC(0x42), /* k */
|
||||
[46] = DEFINE_SC(0x4b), /* l */
|
||||
[47] = DEFINE_SC(0x4c), /* ; */
|
||||
[48] = DEFINE_SC(0x52), /* ' */
|
||||
[49] = DEFINE_SC(0x0e), /* ` */
|
||||
[50] = DEFINE_SC(0x12), /* <left shift> */
|
||||
[51] = DEFINE_SC(0x5d), /* \ */
|
||||
[52] = DEFINE_SC(0x1a), /* z */
|
||||
[53] = DEFINE_SC(0x22), /* x */
|
||||
[54] = DEFINE_SC(0x21), /* c */
|
||||
[55] = DEFINE_SC(0x2a), /* v */
|
||||
[56] = DEFINE_SC(0x32), /* b */
|
||||
[57] = DEFINE_SC(0x31), /* n */
|
||||
[58] = DEFINE_SC(0x3a), /* m */
|
||||
[59] = DEFINE_SC(0x41), /* < */
|
||||
[60] = DEFINE_SC(0x49), /* > */
|
||||
[61] = DEFINE_SC(0x4a), /* / */
|
||||
[62] = DEFINE_SC(0x59), /* <right shift> */
|
||||
[63] = DEFINE_SC(0x7c), /* keypad * */
|
||||
[64] = DEFINE_SC(0x11), /* <left alt> */
|
||||
[65] = DEFINE_SC(0x29), /* <space> */
|
||||
|
||||
[67] = DEFINE_SC(0x05), /* <F1> */
|
||||
[68] = DEFINE_SC(0x06), /* <F2> */
|
||||
[69] = DEFINE_SC(0x04), /* <F3> */
|
||||
[70] = DEFINE_SC(0x0c), /* <F4> */
|
||||
[71] = DEFINE_SC(0x03), /* <F5> */
|
||||
[72] = DEFINE_SC(0x0b), /* <F6> */
|
||||
[73] = DEFINE_SC(0x83), /* <F7> */
|
||||
[74] = DEFINE_SC(0x0a), /* <F8> */
|
||||
[75] = DEFINE_SC(0x01), /* <F9> */
|
||||
[76] = DEFINE_SC(0x09), /* <F10> */
|
||||
|
||||
[79] = DEFINE_SC(0x6c), /* keypad 7 */
|
||||
[80] = DEFINE_SC(0x75), /* keypad 8 */
|
||||
[81] = DEFINE_SC(0x7d), /* keypad 9 */
|
||||
[82] = DEFINE_SC(0x7b), /* keypad - */
|
||||
[83] = DEFINE_SC(0x6b), /* keypad 4 */
|
||||
[84] = DEFINE_SC(0x73), /* keypad 5 */
|
||||
[85] = DEFINE_SC(0x74), /* keypad 6 */
|
||||
[86] = DEFINE_SC(0x79), /* keypad + */
|
||||
[87] = DEFINE_SC(0x69), /* keypad 1 */
|
||||
[88] = DEFINE_SC(0x72), /* keypad 2 */
|
||||
[89] = DEFINE_SC(0x7a), /* keypad 3 */
|
||||
[90] = DEFINE_SC(0x70), /* keypad 0 */
|
||||
[91] = DEFINE_SC(0x71), /* keypad . */
|
||||
|
||||
[94] = DEFINE_SC(0x61), /* <INT 1> */
|
||||
[95] = DEFINE_SC(0x78), /* <F11> */
|
||||
[96] = DEFINE_SC(0x07), /* <F12> */
|
||||
|
||||
[104] = DEFINE_ESC(0x5a), /* keypad <enter> */
|
||||
[105] = DEFINE_ESC(0x14), /* <right ctrl> */
|
||||
[106] = DEFINE_ESC(0x4a), /* keypad / */
|
||||
[108] = DEFINE_ESC(0x11), /* <right alt> */
|
||||
[110] = DEFINE_ESC(0x6c), /* <home> */
|
||||
[111] = DEFINE_ESC(0x75), /* <up> */
|
||||
[112] = DEFINE_ESC(0x7d), /* <pag up> */
|
||||
[113] = DEFINE_ESC(0x6b), /* <left> */
|
||||
[114] = DEFINE_ESC(0x74), /* <right> */
|
||||
[115] = DEFINE_ESC(0x69), /* <end> */
|
||||
[116] = DEFINE_ESC(0x72), /* <down> */
|
||||
[117] = DEFINE_ESC(0x7a), /* <pag down> */
|
||||
[118] = DEFINE_ESC(0x70), /* <ins> */
|
||||
[119] = DEFINE_ESC(0x71), /* <delete> */
|
||||
};
|
||||
|
||||
static cairo_surface_t *surface;
|
||||
static bool done;
|
||||
|
||||
static const struct set2_scancode *to_code(u8 scancode)
|
||||
{
|
||||
return &keymap[scancode];
|
||||
}
|
||||
|
||||
static gboolean
|
||||
kvm_gtk_configure_event(GtkWidget * widget, GdkEventConfigure * event, gpointer data)
|
||||
{
|
||||
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 gboolean kvm_gtk_draw(GtkWidget *widget, cairo_t *cr, gpointer data)
|
||||
{
|
||||
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 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)
|
||||
{
|
||||
struct framebuffer *fb = p;
|
||||
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();
|
||||
|
||||
done = true;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int kvm_gtk_start(struct framebuffer *fb)
|
||||
{
|
||||
pthread_t thread;
|
||||
|
||||
if (pthread_create(&thread, NULL, kvm_gtk_thread, fb) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_gtk_stop(struct framebuffer *fb)
|
||||
{
|
||||
gtk_main_quit();
|
||||
|
||||
while (!done)
|
||||
sleep(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct fb_target_operations kvm_gtk_ops = {
|
||||
.start = kvm_gtk_start,
|
||||
.stop = kvm_gtk_stop,
|
||||
};
|
||||
|
||||
int kvm_gtk_init(struct kvm *kvm)
|
||||
{
|
||||
struct framebuffer *fb;
|
||||
|
||||
if (!kvm->cfg.gtk)
|
||||
return 0;
|
||||
|
||||
fb = vesa__init(kvm);
|
||||
if (IS_ERR(fb)) {
|
||||
pr_err("vesa__init() failed with error %ld\n", PTR_ERR(fb));
|
||||
return PTR_ERR(fb);
|
||||
}
|
||||
|
||||
return fb__attach(fb, &kvm_gtk_ops);
|
||||
}
|
||||
|
||||
int kvm_gtk_exit(struct kvm *kvm)
|
||||
{
|
||||
if (kvm->cfg.gtk)
|
||||
return kvm_gtk_stop(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_init(kvm_gtk_init);
|
||||
dev_exit(kvm_gtk_exit);
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user