xref: /kvmtool/ui/gtk3.c (revision 369c27e68300a6cf0a98f7455a81b7e4473c7a8b)
1 #include "kvm/gtk3.h"
2 
3 #include "kvm/framebuffer.h"
4 #include "kvm/kvm-cpu.h"
5 #include "kvm/i8042.h"
6 #include "kvm/vesa.h"
7 #include "kvm/kvm.h"
8 
9 #include <gtk/gtk.h>
10 #include <pthread.h>
11 #include <linux/err.h>
12 
13 #define FRAME_RATE			25
14 
15 #define SCANCODE_UNKNOWN		0
16 #define SCANCODE_NORMAL			1
17 #define SCANCODE_ESCAPED		2
18 #define SCANCODE_KEY_PAUSE		3
19 #define SCANCODE_KEY_PRNTSCRN		4
20 
21 struct set2_scancode {
22 	u8 code;
23 	u8 type;
24 };
25 
26 #define DEFINE_SC(_code) {		\
27 	.code = _code,			\
28 	.type = SCANCODE_NORMAL,	\
29 }
30 
31 /* escaped scancodes */
32 #define DEFINE_ESC(_code) {		\
33 	.code = _code,			\
34 	.type = SCANCODE_ESCAPED,	\
35 }
36 
37 static const struct set2_scancode keymap[256] = {
38 	[9]	= DEFINE_SC(0x76),	/* <esc> */
39 	[10]	= DEFINE_SC(0x16),	/* 1 */
40 	[11]	= DEFINE_SC(0x1e),	/* 2 */
41 	[12]	= DEFINE_SC(0x26),	/* 3 */
42 	[13]	= DEFINE_SC(0x25),	/* 4 */
43 	[14]	= DEFINE_SC(0x2e),	/* 5 */
44 	[15]	= DEFINE_SC(0x36),	/* 6 */
45 	[16]	= DEFINE_SC(0x3d),	/* 7 */
46 	[17]	= DEFINE_SC(0x3e),	/* 8 */
47 	[18]	= DEFINE_SC(0x46),	/* 9 */
48 	[19]	= DEFINE_SC(0x45),	/* 9 */
49 	[20]	= DEFINE_SC(0x4e),	/* - */
50 	[21]	= DEFINE_SC(0x55),	/* + */
51 	[22]	= DEFINE_SC(0x66),	/* <backspace> */
52 	[23]	= DEFINE_SC(0x0d),	/* <tab> */
53 	[24]	= DEFINE_SC(0x15),	/* q */
54 	[25]	= DEFINE_SC(0x1d),	/* w */
55 	[26]	= DEFINE_SC(0x24),	/* e */
56 	[27]	= DEFINE_SC(0x2d),	/* r */
57 	[28]	= DEFINE_SC(0x2c),	/* t */
58 	[29]	= DEFINE_SC(0x35),	/* y */
59 	[30]	= DEFINE_SC(0x3c),	/* u */
60 	[31]	= DEFINE_SC(0x43),	/* i */
61 	[32]	= DEFINE_SC(0x44),	/* o */
62 	[33]	= DEFINE_SC(0x4d),	/* p */
63 	[34]	= DEFINE_SC(0x54),	/* [ */
64 	[35]	= DEFINE_SC(0x5b),	/* ] */
65 	[36]	= DEFINE_SC(0x5a),	/* <enter> */
66 	[37]	= DEFINE_SC(0x14),	/* <left ctrl> */
67 	[38]	= DEFINE_SC(0x1c),	/* a */
68 	[39]	= DEFINE_SC(0x1b),	/* s */
69 	[40]	= DEFINE_SC(0x23),	/* d */
70 	[41]	= DEFINE_SC(0x2b),	/* f */
71 	[42]	= DEFINE_SC(0x34),	/* g */
72 	[43]	= DEFINE_SC(0x33),	/* h */
73 	[44]	= DEFINE_SC(0x3b),	/* j */
74 	[45]	= DEFINE_SC(0x42),	/* k */
75 	[46]	= DEFINE_SC(0x4b),	/* l */
76 	[47]	= DEFINE_SC(0x4c),	/* ; */
77 	[48]	= DEFINE_SC(0x52),	/* ' */
78 	[49]	= DEFINE_SC(0x0e),	/* ` */
79 	[50]	= DEFINE_SC(0x12),	/* <left shift> */
80 	[51]	= DEFINE_SC(0x5d),	/* \ */
81 	[52]	= DEFINE_SC(0x1a),	/* z */
82 	[53]	= DEFINE_SC(0x22),	/* x */
83 	[54]	= DEFINE_SC(0x21),	/* c */
84 	[55]	= DEFINE_SC(0x2a),	/* v */
85 	[56]	= DEFINE_SC(0x32),	/* b */
86 	[57]	= DEFINE_SC(0x31),	/* n */
87 	[58]	= DEFINE_SC(0x3a),	/* m */
88 	[59]	= DEFINE_SC(0x41),	/* < */
89 	[60]	= DEFINE_SC(0x49),	/* > */
90 	[61]	= DEFINE_SC(0x4a),	/* / */
91 	[62]	= DEFINE_SC(0x59),	/* <right shift> */
92 	[63]	= DEFINE_SC(0x7c),	/* keypad * */
93 	[64]	= DEFINE_SC(0x11),	/* <left alt> */
94 	[65]	= DEFINE_SC(0x29),	/* <space> */
95 
96 	[67]	= DEFINE_SC(0x05),	/* <F1> */
97 	[68]	= DEFINE_SC(0x06),	/* <F2> */
98 	[69]	= DEFINE_SC(0x04),	/* <F3> */
99 	[70]	= DEFINE_SC(0x0c),	/* <F4> */
100 	[71]	= DEFINE_SC(0x03),	/* <F5> */
101 	[72]	= DEFINE_SC(0x0b),	/* <F6> */
102 	[73]	= DEFINE_SC(0x83),	/* <F7> */
103 	[74]	= DEFINE_SC(0x0a),	/* <F8> */
104 	[75]	= DEFINE_SC(0x01),	/* <F9> */
105 	[76]	= DEFINE_SC(0x09),	/* <F10> */
106 
107 	[79]	= DEFINE_SC(0x6c),	/* keypad 7 */
108 	[80]	= DEFINE_SC(0x75),	/* keypad 8 */
109 	[81]	= DEFINE_SC(0x7d),	/* keypad 9 */
110 	[82]	= DEFINE_SC(0x7b),	/* keypad - */
111 	[83]	= DEFINE_SC(0x6b),	/* keypad 4 */
112 	[84]	= DEFINE_SC(0x73),	/* keypad 5 */
113 	[85]	= DEFINE_SC(0x74),	/* keypad 6 */
114 	[86]	= DEFINE_SC(0x79),	/* keypad + */
115 	[87]	= DEFINE_SC(0x69),	/* keypad 1 */
116 	[88]	= DEFINE_SC(0x72),	/* keypad 2 */
117 	[89]	= DEFINE_SC(0x7a),	/* keypad 3 */
118 	[90]	= DEFINE_SC(0x70),	/* keypad 0 */
119 	[91]	= DEFINE_SC(0x71),	/* keypad . */
120 
121 	[94]	= DEFINE_SC(0x61),	/* <INT 1> */
122 	[95]	= DEFINE_SC(0x78),	/* <F11> */
123 	[96]	= DEFINE_SC(0x07),	/* <F12> */
124 
125 	[104]	= DEFINE_ESC(0x5a),	/* keypad <enter> */
126 	[105]	= DEFINE_ESC(0x14),	/* <right ctrl> */
127 	[106]	= DEFINE_ESC(0x4a),	/* keypad / */
128 	[108]	= DEFINE_ESC(0x11),	/* <right alt> */
129 	[110]	= DEFINE_ESC(0x6c),	/* <home> */
130 	[111]	= DEFINE_ESC(0x75),	/* <up> */
131 	[112]	= DEFINE_ESC(0x7d),	/* <pag up> */
132 	[113]	= DEFINE_ESC(0x6b),	/* <left> */
133 	[114]	= DEFINE_ESC(0x74),	/* <right> */
134 	[115]	= DEFINE_ESC(0x69),	/* <end> */
135 	[116]	= DEFINE_ESC(0x72),	/* <down> */
136 	[117]	= DEFINE_ESC(0x7a),	/* <pag down> */
137 	[118]	= DEFINE_ESC(0x70),	/* <ins> */
138 	[119]	= DEFINE_ESC(0x71),	/* <delete> */
139 };
140 
141 static cairo_surface_t	*surface;
142 static bool		done;
143 
to_code(u8 scancode)144 static const struct set2_scancode *to_code(u8 scancode)
145 {
146         return &keymap[scancode];
147 }
148 
149 static gboolean
kvm_gtk_configure_event(GtkWidget * widget,GdkEventConfigure * event,gpointer data)150 kvm_gtk_configure_event(GtkWidget * widget, GdkEventConfigure * event, gpointer data)
151 {
152 	struct framebuffer *fb = data;
153 	int stride;
154 
155 	if (surface)
156 		cairo_surface_destroy(surface);
157 
158 	stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, fb->width);
159 
160 	surface =
161 	    cairo_image_surface_create_for_data((void *) fb->mem,
162 						CAIRO_FORMAT_RGB24,
163 						fb->width,
164 						fb->height,
165 						stride);
166 
167 	return TRUE;
168 }
169 
kvm_gtk_draw(GtkWidget * widget,cairo_t * cr,gpointer data)170 static gboolean kvm_gtk_draw(GtkWidget *widget, cairo_t *cr, gpointer data)
171 {
172 	cairo_set_source_surface(cr, surface, 0, 0);
173 
174 	cairo_paint(cr);
175 
176 	return FALSE;
177 }
178 
kvm_gtk_destroy(void)179 static void kvm_gtk_destroy(void)
180 {
181 	if (surface)
182 		cairo_surface_destroy(surface);
183 
184 	gtk_main_quit();
185 }
186 
kvm_gtk_redraw(GtkWidget * window)187 static gboolean kvm_gtk_redraw(GtkWidget * window)
188 {
189 	gtk_widget_queue_draw(window);
190 
191 	return TRUE;
192 }
193 
194 static gboolean
kvm_gtk_key_press(GtkWidget * widget,GdkEventKey * event,gpointer user_data)195 kvm_gtk_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
196 {
197 	const struct set2_scancode *sc = to_code(event->hardware_keycode);
198 
199         switch (sc->type) {
200         case SCANCODE_ESCAPED:
201                 kbd_queue(0xe0);
202                 /* fallthrough */
203         case SCANCODE_NORMAL:
204                 kbd_queue(sc->code);
205                 break;
206         case SCANCODE_KEY_PAUSE:
207                 kbd_queue(0xe1);
208                 kbd_queue(0x14);
209                 kbd_queue(0x77);
210                 kbd_queue(0xe1);
211                 kbd_queue(0xf0);
212                 kbd_queue(0x14);
213                 kbd_queue(0x77);
214                 break;
215         case SCANCODE_KEY_PRNTSCRN:
216                 kbd_queue(0xe0);
217                 kbd_queue(0x12);
218                 kbd_queue(0xe0);
219                 kbd_queue(0x7c);
220                 break;
221         }
222 
223 	return TRUE;
224 }
225 
kvm_gtk_thread(void * p)226 static void *kvm_gtk_thread(void *p)
227 {
228 	struct framebuffer *fb = p;
229 	GtkWidget *window;
230 	GtkWidget *frame;
231 	GtkWidget *da;
232 
233 	gtk_init(NULL, NULL);
234 
235 	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
236 
237 	gtk_window_set_title(GTK_WINDOW(window), "VM");
238 
239 	g_signal_connect(window, "destroy", G_CALLBACK(kvm_gtk_destroy), NULL);
240 
241 	gtk_container_set_border_width(GTK_CONTAINER(window), 8);
242 
243 	frame = gtk_frame_new(NULL);
244 
245 	gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
246 	gtk_container_add(GTK_CONTAINER(window), frame);
247 
248 	da = gtk_drawing_area_new();
249 
250 	gtk_widget_set_size_request(da, 100, 100);
251 
252 	gtk_container_add(GTK_CONTAINER(frame), da);
253 
254 	g_signal_connect(da, "draw", G_CALLBACK(kvm_gtk_draw), NULL);
255 	g_signal_connect(da, "configure-event",
256 			 G_CALLBACK(kvm_gtk_configure_event), fb);
257 	g_signal_connect(G_OBJECT (window), "key_press_event", G_CALLBACK(kvm_gtk_key_press), NULL);
258 
259 
260 	gtk_widget_set_events(da, gtk_widget_get_events(da)
261 			      | GDK_BUTTON_PRESS_MASK
262 			      | GDK_POINTER_MOTION_MASK
263 			      | GDK_POINTER_MOTION_HINT_MASK);
264 
265 	gtk_widget_show_all(window);
266 
267 	g_timeout_add(1000 / FRAME_RATE, (GSourceFunc) kvm_gtk_redraw, window);
268 
269 	gtk_main();
270 
271 	done = true;
272 
273 	return NULL;
274 }
275 
kvm_gtk_start(struct framebuffer * fb)276 static int kvm_gtk_start(struct framebuffer *fb)
277 {
278 	pthread_t thread;
279 
280 	if (pthread_create(&thread, NULL, kvm_gtk_thread, fb) != 0)
281 		return -1;
282 
283 	return 0;
284 }
285 
kvm_gtk_stop(struct framebuffer * fb)286 static int kvm_gtk_stop(struct framebuffer *fb)
287 {
288 	gtk_main_quit();
289 
290 	while (!done)
291 		sleep(0);
292 
293 	return 0;
294 }
295 
296 static struct fb_target_operations kvm_gtk_ops = {
297 	.start		= kvm_gtk_start,
298 	.stop		= kvm_gtk_stop,
299 };
300 
kvm_gtk_init(struct kvm * kvm)301 int kvm_gtk_init(struct kvm *kvm)
302 {
303 	struct framebuffer *fb;
304 
305 	if (!kvm->cfg.gtk)
306 		return 0;
307 
308 	fb = vesa__init(kvm);
309 	if (IS_ERR(fb)) {
310 		pr_err("vesa__init() failed with error %ld\n", PTR_ERR(fb));
311 		return PTR_ERR(fb);
312 	}
313 
314 	return fb__attach(fb, &kvm_gtk_ops);
315 }
316 
kvm_gtk_exit(struct kvm * kvm)317 int kvm_gtk_exit(struct kvm *kvm)
318 {
319 	if (kvm->cfg.gtk)
320 		return kvm_gtk_stop(NULL);
321 
322 	return 0;
323 }
324 
325 dev_init(kvm_gtk_init);
326 dev_exit(kvm_gtk_exit);
327