17bcceb95SPekka Enberg #include "kvm/gtk3.h"
27bcceb95SPekka Enberg
37bcceb95SPekka Enberg #include "kvm/framebuffer.h"
47bcceb95SPekka Enberg #include "kvm/kvm-cpu.h"
57bcceb95SPekka Enberg #include "kvm/i8042.h"
67bcceb95SPekka Enberg #include "kvm/vesa.h"
77bcceb95SPekka Enberg #include "kvm/kvm.h"
87bcceb95SPekka Enberg
97bcceb95SPekka Enberg #include <gtk/gtk.h>
107bcceb95SPekka Enberg #include <pthread.h>
117bcceb95SPekka Enberg #include <linux/err.h>
127bcceb95SPekka Enberg
137bcceb95SPekka Enberg #define FRAME_RATE 25
147bcceb95SPekka Enberg
157bcceb95SPekka Enberg #define SCANCODE_UNKNOWN 0
167bcceb95SPekka Enberg #define SCANCODE_NORMAL 1
177bcceb95SPekka Enberg #define SCANCODE_ESCAPED 2
187bcceb95SPekka Enberg #define SCANCODE_KEY_PAUSE 3
197bcceb95SPekka Enberg #define SCANCODE_KEY_PRNTSCRN 4
207bcceb95SPekka Enberg
217bcceb95SPekka Enberg struct set2_scancode {
227bcceb95SPekka Enberg u8 code;
237bcceb95SPekka Enberg u8 type;
247bcceb95SPekka Enberg };
257bcceb95SPekka Enberg
267bcceb95SPekka Enberg #define DEFINE_SC(_code) { \
277bcceb95SPekka Enberg .code = _code, \
287bcceb95SPekka Enberg .type = SCANCODE_NORMAL, \
297bcceb95SPekka Enberg }
307bcceb95SPekka Enberg
317bcceb95SPekka Enberg /* escaped scancodes */
327bcceb95SPekka Enberg #define DEFINE_ESC(_code) { \
337bcceb95SPekka Enberg .code = _code, \
347bcceb95SPekka Enberg .type = SCANCODE_ESCAPED, \
357bcceb95SPekka Enberg }
367bcceb95SPekka Enberg
37*369c27e6SAndre Przywara static const struct set2_scancode keymap[256] = {
387bcceb95SPekka Enberg [9] = DEFINE_SC(0x76), /* <esc> */
397bcceb95SPekka Enberg [10] = DEFINE_SC(0x16), /* 1 */
407bcceb95SPekka Enberg [11] = DEFINE_SC(0x1e), /* 2 */
417bcceb95SPekka Enberg [12] = DEFINE_SC(0x26), /* 3 */
427bcceb95SPekka Enberg [13] = DEFINE_SC(0x25), /* 4 */
437bcceb95SPekka Enberg [14] = DEFINE_SC(0x2e), /* 5 */
447bcceb95SPekka Enberg [15] = DEFINE_SC(0x36), /* 6 */
457bcceb95SPekka Enberg [16] = DEFINE_SC(0x3d), /* 7 */
467bcceb95SPekka Enberg [17] = DEFINE_SC(0x3e), /* 8 */
477bcceb95SPekka Enberg [18] = DEFINE_SC(0x46), /* 9 */
487bcceb95SPekka Enberg [19] = DEFINE_SC(0x45), /* 9 */
497bcceb95SPekka Enberg [20] = DEFINE_SC(0x4e), /* - */
507bcceb95SPekka Enberg [21] = DEFINE_SC(0x55), /* + */
517bcceb95SPekka Enberg [22] = DEFINE_SC(0x66), /* <backspace> */
527bcceb95SPekka Enberg [23] = DEFINE_SC(0x0d), /* <tab> */
537bcceb95SPekka Enberg [24] = DEFINE_SC(0x15), /* q */
547bcceb95SPekka Enberg [25] = DEFINE_SC(0x1d), /* w */
557bcceb95SPekka Enberg [26] = DEFINE_SC(0x24), /* e */
567bcceb95SPekka Enberg [27] = DEFINE_SC(0x2d), /* r */
577bcceb95SPekka Enberg [28] = DEFINE_SC(0x2c), /* t */
587bcceb95SPekka Enberg [29] = DEFINE_SC(0x35), /* y */
597bcceb95SPekka Enberg [30] = DEFINE_SC(0x3c), /* u */
607bcceb95SPekka Enberg [31] = DEFINE_SC(0x43), /* i */
617bcceb95SPekka Enberg [32] = DEFINE_SC(0x44), /* o */
627bcceb95SPekka Enberg [33] = DEFINE_SC(0x4d), /* p */
637bcceb95SPekka Enberg [34] = DEFINE_SC(0x54), /* [ */
647bcceb95SPekka Enberg [35] = DEFINE_SC(0x5b), /* ] */
657bcceb95SPekka Enberg [36] = DEFINE_SC(0x5a), /* <enter> */
667bcceb95SPekka Enberg [37] = DEFINE_SC(0x14), /* <left ctrl> */
677bcceb95SPekka Enberg [38] = DEFINE_SC(0x1c), /* a */
687bcceb95SPekka Enberg [39] = DEFINE_SC(0x1b), /* s */
697bcceb95SPekka Enberg [40] = DEFINE_SC(0x23), /* d */
707bcceb95SPekka Enberg [41] = DEFINE_SC(0x2b), /* f */
717bcceb95SPekka Enberg [42] = DEFINE_SC(0x34), /* g */
727bcceb95SPekka Enberg [43] = DEFINE_SC(0x33), /* h */
737bcceb95SPekka Enberg [44] = DEFINE_SC(0x3b), /* j */
747bcceb95SPekka Enberg [45] = DEFINE_SC(0x42), /* k */
757bcceb95SPekka Enberg [46] = DEFINE_SC(0x4b), /* l */
767bcceb95SPekka Enberg [47] = DEFINE_SC(0x4c), /* ; */
777bcceb95SPekka Enberg [48] = DEFINE_SC(0x52), /* ' */
787bcceb95SPekka Enberg [49] = DEFINE_SC(0x0e), /* ` */
797bcceb95SPekka Enberg [50] = DEFINE_SC(0x12), /* <left shift> */
807bcceb95SPekka Enberg [51] = DEFINE_SC(0x5d), /* \ */
817bcceb95SPekka Enberg [52] = DEFINE_SC(0x1a), /* z */
827bcceb95SPekka Enberg [53] = DEFINE_SC(0x22), /* x */
837bcceb95SPekka Enberg [54] = DEFINE_SC(0x21), /* c */
847bcceb95SPekka Enberg [55] = DEFINE_SC(0x2a), /* v */
857bcceb95SPekka Enberg [56] = DEFINE_SC(0x32), /* b */
867bcceb95SPekka Enberg [57] = DEFINE_SC(0x31), /* n */
877bcceb95SPekka Enberg [58] = DEFINE_SC(0x3a), /* m */
887bcceb95SPekka Enberg [59] = DEFINE_SC(0x41), /* < */
897bcceb95SPekka Enberg [60] = DEFINE_SC(0x49), /* > */
907bcceb95SPekka Enberg [61] = DEFINE_SC(0x4a), /* / */
917bcceb95SPekka Enberg [62] = DEFINE_SC(0x59), /* <right shift> */
927bcceb95SPekka Enberg [63] = DEFINE_SC(0x7c), /* keypad * */
937bcceb95SPekka Enberg [64] = DEFINE_SC(0x11), /* <left alt> */
947bcceb95SPekka Enberg [65] = DEFINE_SC(0x29), /* <space> */
957bcceb95SPekka Enberg
967bcceb95SPekka Enberg [67] = DEFINE_SC(0x05), /* <F1> */
977bcceb95SPekka Enberg [68] = DEFINE_SC(0x06), /* <F2> */
987bcceb95SPekka Enberg [69] = DEFINE_SC(0x04), /* <F3> */
997bcceb95SPekka Enberg [70] = DEFINE_SC(0x0c), /* <F4> */
1007bcceb95SPekka Enberg [71] = DEFINE_SC(0x03), /* <F5> */
1017bcceb95SPekka Enberg [72] = DEFINE_SC(0x0b), /* <F6> */
1027bcceb95SPekka Enberg [73] = DEFINE_SC(0x83), /* <F7> */
1037bcceb95SPekka Enberg [74] = DEFINE_SC(0x0a), /* <F8> */
1047bcceb95SPekka Enberg [75] = DEFINE_SC(0x01), /* <F9> */
1057bcceb95SPekka Enberg [76] = DEFINE_SC(0x09), /* <F10> */
1067bcceb95SPekka Enberg
1077bcceb95SPekka Enberg [79] = DEFINE_SC(0x6c), /* keypad 7 */
1087bcceb95SPekka Enberg [80] = DEFINE_SC(0x75), /* keypad 8 */
1097bcceb95SPekka Enberg [81] = DEFINE_SC(0x7d), /* keypad 9 */
1107bcceb95SPekka Enberg [82] = DEFINE_SC(0x7b), /* keypad - */
1117bcceb95SPekka Enberg [83] = DEFINE_SC(0x6b), /* keypad 4 */
1127bcceb95SPekka Enberg [84] = DEFINE_SC(0x73), /* keypad 5 */
1137bcceb95SPekka Enberg [85] = DEFINE_SC(0x74), /* keypad 6 */
1147bcceb95SPekka Enberg [86] = DEFINE_SC(0x79), /* keypad + */
1157bcceb95SPekka Enberg [87] = DEFINE_SC(0x69), /* keypad 1 */
1167bcceb95SPekka Enberg [88] = DEFINE_SC(0x72), /* keypad 2 */
1177bcceb95SPekka Enberg [89] = DEFINE_SC(0x7a), /* keypad 3 */
1187bcceb95SPekka Enberg [90] = DEFINE_SC(0x70), /* keypad 0 */
1197bcceb95SPekka Enberg [91] = DEFINE_SC(0x71), /* keypad . */
1207bcceb95SPekka Enberg
1217bcceb95SPekka Enberg [94] = DEFINE_SC(0x61), /* <INT 1> */
1227bcceb95SPekka Enberg [95] = DEFINE_SC(0x78), /* <F11> */
1237bcceb95SPekka Enberg [96] = DEFINE_SC(0x07), /* <F12> */
1247bcceb95SPekka Enberg
1257bcceb95SPekka Enberg [104] = DEFINE_ESC(0x5a), /* keypad <enter> */
1267bcceb95SPekka Enberg [105] = DEFINE_ESC(0x14), /* <right ctrl> */
1277bcceb95SPekka Enberg [106] = DEFINE_ESC(0x4a), /* keypad / */
1287bcceb95SPekka Enberg [108] = DEFINE_ESC(0x11), /* <right alt> */
1297bcceb95SPekka Enberg [110] = DEFINE_ESC(0x6c), /* <home> */
1307bcceb95SPekka Enberg [111] = DEFINE_ESC(0x75), /* <up> */
1317bcceb95SPekka Enberg [112] = DEFINE_ESC(0x7d), /* <pag up> */
1327bcceb95SPekka Enberg [113] = DEFINE_ESC(0x6b), /* <left> */
1337bcceb95SPekka Enberg [114] = DEFINE_ESC(0x74), /* <right> */
1347bcceb95SPekka Enberg [115] = DEFINE_ESC(0x69), /* <end> */
1357bcceb95SPekka Enberg [116] = DEFINE_ESC(0x72), /* <down> */
1367bcceb95SPekka Enberg [117] = DEFINE_ESC(0x7a), /* <pag down> */
1377bcceb95SPekka Enberg [118] = DEFINE_ESC(0x70), /* <ins> */
1387bcceb95SPekka Enberg [119] = DEFINE_ESC(0x71), /* <delete> */
1397bcceb95SPekka Enberg };
1407bcceb95SPekka Enberg
1417bcceb95SPekka Enberg static cairo_surface_t *surface;
1427bcceb95SPekka Enberg static bool done;
1437bcceb95SPekka Enberg
to_code(u8 scancode)1447bcceb95SPekka Enberg static const struct set2_scancode *to_code(u8 scancode)
1457bcceb95SPekka Enberg {
1467bcceb95SPekka Enberg return &keymap[scancode];
1477bcceb95SPekka Enberg }
1487bcceb95SPekka Enberg
1497bcceb95SPekka Enberg static gboolean
kvm_gtk_configure_event(GtkWidget * widget,GdkEventConfigure * event,gpointer data)1507bcceb95SPekka Enberg kvm_gtk_configure_event(GtkWidget * widget, GdkEventConfigure * event, gpointer data)
1517bcceb95SPekka Enberg {
1527bcceb95SPekka Enberg struct framebuffer *fb = data;
1537bcceb95SPekka Enberg int stride;
1547bcceb95SPekka Enberg
1557bcceb95SPekka Enberg if (surface)
1567bcceb95SPekka Enberg cairo_surface_destroy(surface);
1577bcceb95SPekka Enberg
1587bcceb95SPekka Enberg stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, fb->width);
1597bcceb95SPekka Enberg
1607bcceb95SPekka Enberg surface =
1617bcceb95SPekka Enberg cairo_image_surface_create_for_data((void *) fb->mem,
1627bcceb95SPekka Enberg CAIRO_FORMAT_RGB24,
1637bcceb95SPekka Enberg fb->width,
1647bcceb95SPekka Enberg fb->height,
1657bcceb95SPekka Enberg stride);
1667bcceb95SPekka Enberg
1677bcceb95SPekka Enberg return TRUE;
1687bcceb95SPekka Enberg }
1697bcceb95SPekka Enberg
kvm_gtk_draw(GtkWidget * widget,cairo_t * cr,gpointer data)1707bcceb95SPekka Enberg static gboolean kvm_gtk_draw(GtkWidget *widget, cairo_t *cr, gpointer data)
1717bcceb95SPekka Enberg {
1727bcceb95SPekka Enberg cairo_set_source_surface(cr, surface, 0, 0);
1737bcceb95SPekka Enberg
1747bcceb95SPekka Enberg cairo_paint(cr);
1757bcceb95SPekka Enberg
1767bcceb95SPekka Enberg return FALSE;
1777bcceb95SPekka Enberg }
1787bcceb95SPekka Enberg
kvm_gtk_destroy(void)1797bcceb95SPekka Enberg static void kvm_gtk_destroy(void)
1807bcceb95SPekka Enberg {
1817bcceb95SPekka Enberg if (surface)
1827bcceb95SPekka Enberg cairo_surface_destroy(surface);
1837bcceb95SPekka Enberg
1847bcceb95SPekka Enberg gtk_main_quit();
1857bcceb95SPekka Enberg }
1867bcceb95SPekka Enberg
kvm_gtk_redraw(GtkWidget * window)1877bcceb95SPekka Enberg static gboolean kvm_gtk_redraw(GtkWidget * window)
1887bcceb95SPekka Enberg {
1897bcceb95SPekka Enberg gtk_widget_queue_draw(window);
1907bcceb95SPekka Enberg
1917bcceb95SPekka Enberg return TRUE;
1927bcceb95SPekka Enberg }
1937bcceb95SPekka Enberg
1947bcceb95SPekka Enberg static gboolean
kvm_gtk_key_press(GtkWidget * widget,GdkEventKey * event,gpointer user_data)1957bcceb95SPekka Enberg kvm_gtk_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
1967bcceb95SPekka Enberg {
1977bcceb95SPekka Enberg const struct set2_scancode *sc = to_code(event->hardware_keycode);
1987bcceb95SPekka Enberg
1997bcceb95SPekka Enberg switch (sc->type) {
2007bcceb95SPekka Enberg case SCANCODE_ESCAPED:
2017bcceb95SPekka Enberg kbd_queue(0xe0);
2027bcceb95SPekka Enberg /* fallthrough */
2037bcceb95SPekka Enberg case SCANCODE_NORMAL:
2047bcceb95SPekka Enberg kbd_queue(sc->code);
2057bcceb95SPekka Enberg break;
2067bcceb95SPekka Enberg case SCANCODE_KEY_PAUSE:
2077bcceb95SPekka Enberg kbd_queue(0xe1);
2087bcceb95SPekka Enberg kbd_queue(0x14);
2097bcceb95SPekka Enberg kbd_queue(0x77);
2107bcceb95SPekka Enberg kbd_queue(0xe1);
2117bcceb95SPekka Enberg kbd_queue(0xf0);
2127bcceb95SPekka Enberg kbd_queue(0x14);
2137bcceb95SPekka Enberg kbd_queue(0x77);
2147bcceb95SPekka Enberg break;
2157bcceb95SPekka Enberg case SCANCODE_KEY_PRNTSCRN:
2167bcceb95SPekka Enberg kbd_queue(0xe0);
2177bcceb95SPekka Enberg kbd_queue(0x12);
2187bcceb95SPekka Enberg kbd_queue(0xe0);
2197bcceb95SPekka Enberg kbd_queue(0x7c);
2207bcceb95SPekka Enberg break;
2217bcceb95SPekka Enberg }
2227bcceb95SPekka Enberg
2237bcceb95SPekka Enberg return TRUE;
2247bcceb95SPekka Enberg }
2257bcceb95SPekka Enberg
kvm_gtk_thread(void * p)2267bcceb95SPekka Enberg static void *kvm_gtk_thread(void *p)
2277bcceb95SPekka Enberg {
2287bcceb95SPekka Enberg struct framebuffer *fb = p;
2297bcceb95SPekka Enberg GtkWidget *window;
2307bcceb95SPekka Enberg GtkWidget *frame;
2317bcceb95SPekka Enberg GtkWidget *da;
2327bcceb95SPekka Enberg
2337bcceb95SPekka Enberg gtk_init(NULL, NULL);
2347bcceb95SPekka Enberg
2357bcceb95SPekka Enberg window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2367bcceb95SPekka Enberg
2377bcceb95SPekka Enberg gtk_window_set_title(GTK_WINDOW(window), "VM");
2387bcceb95SPekka Enberg
2397bcceb95SPekka Enberg g_signal_connect(window, "destroy", G_CALLBACK(kvm_gtk_destroy), NULL);
2407bcceb95SPekka Enberg
2417bcceb95SPekka Enberg gtk_container_set_border_width(GTK_CONTAINER(window), 8);
2427bcceb95SPekka Enberg
2437bcceb95SPekka Enberg frame = gtk_frame_new(NULL);
2447bcceb95SPekka Enberg
2457bcceb95SPekka Enberg gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
2467bcceb95SPekka Enberg gtk_container_add(GTK_CONTAINER(window), frame);
2477bcceb95SPekka Enberg
2487bcceb95SPekka Enberg da = gtk_drawing_area_new();
2497bcceb95SPekka Enberg
2507bcceb95SPekka Enberg gtk_widget_set_size_request(da, 100, 100);
2517bcceb95SPekka Enberg
2527bcceb95SPekka Enberg gtk_container_add(GTK_CONTAINER(frame), da);
2537bcceb95SPekka Enberg
2547bcceb95SPekka Enberg g_signal_connect(da, "draw", G_CALLBACK(kvm_gtk_draw), NULL);
2557bcceb95SPekka Enberg g_signal_connect(da, "configure-event",
2567bcceb95SPekka Enberg G_CALLBACK(kvm_gtk_configure_event), fb);
2577bcceb95SPekka Enberg g_signal_connect(G_OBJECT (window), "key_press_event", G_CALLBACK(kvm_gtk_key_press), NULL);
2587bcceb95SPekka Enberg
2597bcceb95SPekka Enberg
2607bcceb95SPekka Enberg gtk_widget_set_events(da, gtk_widget_get_events(da)
2617bcceb95SPekka Enberg | GDK_BUTTON_PRESS_MASK
2627bcceb95SPekka Enberg | GDK_POINTER_MOTION_MASK
2637bcceb95SPekka Enberg | GDK_POINTER_MOTION_HINT_MASK);
2647bcceb95SPekka Enberg
2657bcceb95SPekka Enberg gtk_widget_show_all(window);
2667bcceb95SPekka Enberg
2677bcceb95SPekka Enberg g_timeout_add(1000 / FRAME_RATE, (GSourceFunc) kvm_gtk_redraw, window);
2687bcceb95SPekka Enberg
2697bcceb95SPekka Enberg gtk_main();
2707bcceb95SPekka Enberg
2717bcceb95SPekka Enberg done = true;
2727bcceb95SPekka Enberg
2737bcceb95SPekka Enberg return NULL;
2747bcceb95SPekka Enberg }
2757bcceb95SPekka Enberg
kvm_gtk_start(struct framebuffer * fb)2767bcceb95SPekka Enberg static int kvm_gtk_start(struct framebuffer *fb)
2777bcceb95SPekka Enberg {
2787bcceb95SPekka Enberg pthread_t thread;
2797bcceb95SPekka Enberg
2807bcceb95SPekka Enberg if (pthread_create(&thread, NULL, kvm_gtk_thread, fb) != 0)
2817bcceb95SPekka Enberg return -1;
2827bcceb95SPekka Enberg
2837bcceb95SPekka Enberg return 0;
2847bcceb95SPekka Enberg }
2857bcceb95SPekka Enberg
kvm_gtk_stop(struct framebuffer * fb)2867bcceb95SPekka Enberg static int kvm_gtk_stop(struct framebuffer *fb)
2877bcceb95SPekka Enberg {
2887bcceb95SPekka Enberg gtk_main_quit();
2897bcceb95SPekka Enberg
2907bcceb95SPekka Enberg while (!done)
2917bcceb95SPekka Enberg sleep(0);
2927bcceb95SPekka Enberg
2937bcceb95SPekka Enberg return 0;
2947bcceb95SPekka Enberg }
2957bcceb95SPekka Enberg
2967bcceb95SPekka Enberg static struct fb_target_operations kvm_gtk_ops = {
2977bcceb95SPekka Enberg .start = kvm_gtk_start,
2987bcceb95SPekka Enberg .stop = kvm_gtk_stop,
2997bcceb95SPekka Enberg };
3007bcceb95SPekka Enberg
kvm_gtk_init(struct kvm * kvm)3017bcceb95SPekka Enberg int kvm_gtk_init(struct kvm *kvm)
3027bcceb95SPekka Enberg {
3037bcceb95SPekka Enberg struct framebuffer *fb;
3047bcceb95SPekka Enberg
3057bcceb95SPekka Enberg if (!kvm->cfg.gtk)
3067bcceb95SPekka Enberg return 0;
3077bcceb95SPekka Enberg
3087bcceb95SPekka Enberg fb = vesa__init(kvm);
3097bcceb95SPekka Enberg if (IS_ERR(fb)) {
3107bcceb95SPekka Enberg pr_err("vesa__init() failed with error %ld\n", PTR_ERR(fb));
3117bcceb95SPekka Enberg return PTR_ERR(fb);
3127bcceb95SPekka Enberg }
3137bcceb95SPekka Enberg
3147bcceb95SPekka Enberg return fb__attach(fb, &kvm_gtk_ops);
3157bcceb95SPekka Enberg }
3167bcceb95SPekka Enberg
kvm_gtk_exit(struct kvm * kvm)3177bcceb95SPekka Enberg int kvm_gtk_exit(struct kvm *kvm)
3187bcceb95SPekka Enberg {
3197bcceb95SPekka Enberg if (kvm->cfg.gtk)
3207bcceb95SPekka Enberg return kvm_gtk_stop(NULL);
3217bcceb95SPekka Enberg
3227bcceb95SPekka Enberg return 0;
3237bcceb95SPekka Enberg }
3247bcceb95SPekka Enberg
3257bcceb95SPekka Enberg dev_init(kvm_gtk_init);
3267bcceb95SPekka Enberg dev_exit(kvm_gtk_exit);
327