0.7.2-alt1
[qemu] / qemu-gtk / gtk2.c
1 /*
2  * QEMU GTK2 display driver
3  * based on SDL driver by Fabrice
4  * 
5  * Copyright (c) 2005 Jim Brown
6  * 
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  */
25 #include "vl.h"
26
27 #include <gtk/gtk.h>
28 #include <gdk/gdk.h>
29
30 #include "fullscreen.h"
31
32 /* define our own bitshift enums to allow qemugtk to know difference between left and right alt - something gtk doesnt provide in its modifiers mask. this uses qemu's own modifier_state[] map in order to guess correctly */
33 typedef enum
34 {
35         gtkshiftleft = 1 << 0,
36         gtkshiftright = 1 << 1,
37         gtkcontrolleft = 1 << 2,
38         gtkcontrolright = 1 << 3,
39         gtkaltleft = 1 << 4,
40         gtkaltright = 1 << 5,
41         gtkcapslock = 1 << 6
42 } gtk2keymod;
43
44
45 static GtkWidget *window, *swindow;
46 static GtkWidget *event_port, *menubar;
47 static GdkImage *image=NULL;
48 static GdkCursor *invisible_cursor;
49 static int ox = 0, oy = 0;
50 static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
51 static int gui_rgrab; /* if true, all keyboard/mouse events are grabbed */
52 static int last_vm_running;
53 static int gui_saved_grab;
54 static int gui_fullscreen;
55 static int gui_key_modifier_pressed;
56 static int gui_keysym;
57 static int gui_fullscreen_initial_grab;
58 static int gui_grab_code = gtkaltleft | gtkcontrolleft;
59 static uint8_t modifiers_state[256];
60 static int window_resize = 0;
61 static unsigned int cw, ch;
62 static gint win_x, win_y, win_w, win_h;
63 static GtkWidget * box; /* because GtkWindow/GtkBin holds only one widget */
64
65 static gboolean gtk2_expose(GtkWidget *wid, GdkEventExpose *event)
66 {
67     if (gui_fullscreen && wid == event_port) return FALSE;
68     if (!gui_fullscreen && wid == window) return FALSE;
69     gdk_draw_image(wid->window, wid->style->fg_gc[GTK_WIDGET_STATE(wid)], image, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height);
70     return TRUE;
71 }
72
73 static void gtk2_update(DisplayState *ds, int x, int y, int w, int h)
74 {
75     //    printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
76     GdkEventExpose ev;
77     ev.area.x = x;
78     ev.area.y = y;
79     ev.area.width = w;
80     ev.area.height = h;
81     /* catch the first resize done by the init function - make sure we don't **
82     ** try to draw an image until screen has been finalized/realized/etc */
83     if (event_port->window != NULL)
84     {
85         if (gui_fullscreen)
86             gtk2_expose(window, &ev);
87         else
88             gtk2_expose(event_port, &ev);
89     }
90 }
91
92 static void gtk2_resize(DisplayState *ds, int w, int h)
93 {
94
95     //    printf(" resizing to %d %d\n", w, h);
96
97     if (gui_fullscreen)
98     {
99         if (cw != w || ch != h)
100         {
101             fullscreen_switch(win_x, win_y, w, h); /* changing video modes */
102 /* apparently GTK enjoys moving static windows all over the place while
103 they are being resized - so we have to be tricky */
104             //gtk_window_move(GTK_WINDOW(window), win_x, win_y);
105             //gtk_window_move(GTK_WINDOW(window), 0, 0);
106             gdk_window_move_resize(window->window, 0, 0, w, h);
107         }
108     }
109
110     cw = w; ch = h;
111
112     if (image)
113          g_object_unref(image);
114
115 /* gdk_visual_get_best_with_depth() ??? but then how to paint onto window? */
116     image = gdk_image_new(GDK_IMAGE_NORMAL, gdk_visual_get_system(), w, h);
117     gdk_image_set_colormap(image, gdk_colormap_get_system());
118
119     gtk_widget_set_size_request(event_port, w, h);
120     if (window_resize)
121         gdk_window_move_resize(window->window, win_x, win_y, w+25, h+50);
122
123     ds->data = image->mem;
124     ds->linesize = image->bpl;
125     ds->depth = image->bits_per_pixel;
126     ds->width = w;
127     ds->height = h;
128     gtk2_update(ds, 0, 0, w, h);
129 }
130
131 static gboolean gtk2_config(GtkWidget *wid, GdkEventConfigure *ev, DisplayState *ds)
132 {
133     if (!gui_fullscreen)
134     {
135         win_x = ev->x;
136         win_y = ev->y;
137         win_w = ev->width;
138         win_h = ev->height;
139     }
140     return FALSE;
141 }
142
143 /* generic keyboard conversion */
144
145 #include "gdk_keysym.h"
146 #include "keymaps.c"
147
148 static kbd_layout_t *kbd_layout = NULL;
149
150 static uint8_t gtk2_keyevent_to_keycode_generic(const GdkEventKey *ev)
151 {
152     int keysym;
153     /* workaround for X11+SDL bug with AltGR - is it still needed for Gtk2? */
154     keysym = ev->keyval;
155     if (keysym == 0 && ev->hardware_keycode == 113)
156         keysym = GDK_Mode_switch;
157     return keysym2scancode(kbd_layout, keysym);
158 }
159
160 /* specific keyboard conversions from scan codes */
161
162 #if defined(_WIN32)
163
164 #include <windows.h>
165
166 static UINT vk2scan(UINT vk)
167 {
168         return MapVirtualKey(vk,0);
169 }
170 static uint8_t gtk2_keyevent_to_keycode(const GdkEventKey *ev)
171 {   
172     return (uint8_t)vk2scan((UINT)(ev->hardware_keycode));
173 }
174
175 #else
176
177 static const uint8_t x_keycode_to_pc_keycode[61] = {
178    0xc7,      /*  97  Home   */
179    0xc8,      /*  98  Up     */
180    0xc9,      /*  99  PgUp   */
181    0xcb,      /* 100  Left   */
182    0x4c,        /* 101  KP-5   */
183    0xcd,      /* 102  Right  */
184    0xcf,      /* 103  End    */
185    0xd0,      /* 104  Down   */
186    0xd1,      /* 105  PgDn   */
187    0xd2,      /* 106  Ins    */
188    0xd3,      /* 107  Del    */
189    0x9c,      /* 108  Enter  */
190    0x9d,      /* 109  Ctrl-R */
191    0x0,       /* 110  Pause  */
192    0xb7,      /* 111  Print  */
193    0xb5,      /* 112  Divide */
194    0xb8,      /* 113  Alt-R  */
195    0xc6,      /* 114  Break  */   
196    0xdb,         /* 115 windows left button */
197    0xdc,         /* 116 windows right button */
198    0xdd,         /* 117 right menu button */
199    0x0,         /* 118 */
200    0x0,         /* 119 */
201    0x70,         /* 120 Hiragana_Katakana */
202    0x0,         /* 121 */
203    0x0,         /* 122 */
204    0x73,         /* 123 backslash */
205    0x0,         /* 124 */
206    0x0,         /* 125 */
207    0x0,         /* 126 */
208    0x0,         /* 127 */
209    0x0,         /* 128 */
210    0x79,         /* 129 Henkan */
211    0x0,         /* 130 */
212    0x7b,         /* 131 Muhenkan */
213    0x0,         /* 132 */
214    0x7d,         /* 133 Yen */
215    0x0,         /* 134 */
216    0x0,         /* 135 */
217    0x47,         /* 136 KP_7 */
218    0x48,         /* 137 KP_8 */
219    0x49,         /* 138 KP_9 */
220    0x4b,         /* 139 KP_4 */
221    0x4c,         /* 140 KP_5 */
222    0x4d,         /* 141 KP_6 */
223    0x4f,         /* 142 KP_1 */
224    0x50,         /* 143 KP_2 */
225    0x51,         /* 144 KP_3 */
226    0x52,         /* 145 KP_0 */
227    0x53,         /* 146 KP_. */
228    0x47,         /* 147 KP_HOME */
229    0x48,         /* 148 KP_UP */
230    0x49,         /* 149 KP_PgUp */
231    0x4b,         /* 150 KP_Left */
232    0x4c,         /* 151 KP_ */
233    0x4d,         /* 152 KP_Right */
234    0x4f,         /* 153 KP_End */
235    0x50,         /* 154 KP_Down */
236    0x51,         /* 155 KP_PgDn */
237    0x52,         /* 156 KP_Ins */
238    0x53,         /* 157 KP_Del */
239 };
240
241 static uint8_t gtk2_keyevent_to_keycode(const GdkEventKey *ev)
242 {
243     int keycode;
244
245     keycode = ev->hardware_keycode;
246
247     if (keycode < 9) {
248         keycode = 0;
249     } else if (keycode < 97) {
250         keycode -= 8; /* just an offset */
251     } else if (keycode < 158) {
252         /* use conversion table */
253         keycode = x_keycode_to_pc_keycode[keycode - 97];
254     } else {
255         keycode = 0;
256     }
257     return keycode;
258 }
259
260 #endif
261
262 static void reset_keys(void)
263 {
264     int i;
265     for(i = 0; i < 256; i++) {
266         if (modifiers_state[i]) {
267             if (i & 0x80)
268                 kbd_put_keycode(0xe0);
269             kbd_put_keycode(i | 0x80);
270             modifiers_state[i] = 0;
271         }
272     }
273 }
274
275 /* convert GDK modifiers and invoke ugly hack to distinguish
276 between left and right shift/control/alt */
277 static guint gtk2_GetModState(const GdkEventKey *ev)
278 {
279         guint key = 0, keyval = ev->keyval, state = ev->state;
280         switch(keyval)
281         {
282                 case GDK_Shift_L:
283                         if (ev->type != GDK_KEY_RELEASE)
284                                 key |= gtkshiftleft;
285                         keyval = 1;
286                         break;
287                 case GDK_Shift_R:
288                         if (ev->type != GDK_KEY_RELEASE)
289                                 key |= gtkshiftright;
290                         keyval = 1;
291                         break;
292                 case GDK_Control_L:
293                         if (ev->type != GDK_KEY_RELEASE)
294                                 key |= gtkcontrolleft;
295                         keyval = 2;
296                         break;
297                 case GDK_Control_R:
298                         if (ev->type != GDK_KEY_RELEASE)
299                                 key |= gtkcontrolright;
300                         keyval = 2;
301                         break;
302                 case GDK_Alt_L:
303                         if (ev->type != GDK_KEY_RELEASE)
304                                 key |= gtkaltleft;
305                         keyval = 3;
306                         break;
307                 case GDK_Alt_R:
308                         if (ev->type != GDK_KEY_RELEASE)
309                                 key |= gtkaltright;
310                         keyval = 3;
311                         break;
312                 case GDK_Caps_Lock:
313                         if (ev->type != GDK_KEY_RELEASE)
314                                 key |= gtkcapslock;
315                         keyval = 4;
316                         break;
317                 default:
318                         keyval = 0;
319                         break;
320         }
321         if (keyval != 1 && (state & GDK_SHIFT_MASK))
322         {
323                 if (modifiers_state[0x2a])
324                         key |= gtkshiftleft;
325                 if (modifiers_state[0x36])
326                         key |= gtkshiftright;
327         }
328         if (keyval != 2 && (state & GDK_CONTROL_MASK))
329         {
330                 if (modifiers_state[0x1d])
331                         key |= gtkcontrolleft;
332                 if (modifiers_state[0x9d])
333                         key |= gtkcontrolright;
334         }
335         if (keyval != 3 && (state & GDK_MOD1_MASK)) /* fixme: need to do a check to make sure that alt is mapped to GDK_MOD1_MASK in the GDK_Keymap */
336         {
337                 if (modifiers_state[0x38])
338                         key |= gtkaltleft;
339                 if (modifiers_state[0xb8])
340                         key |= gtkaltright;
341         }
342         if (keyval != 4 && (state & GDK_LOCK_MASK))
343                 key |= gtkcapslock;
344         return key;
345 }
346
347 static void gtk2_process_key(GdkEventKey *ev)
348 {
349     int keycode, v;
350
351     if (ev->keyval == GDK_Pause) {
352         /* specific case */
353         v = 0;
354         if (ev->type == GDK_KEY_RELEASE)
355             v |= 0x80;
356         kbd_put_keycode(0xe1);
357         kbd_put_keycode(0x1d | v);
358         kbd_put_keycode(0x45 | v);
359         return;
360     }
361
362     if (kbd_layout) {
363         keycode = gtk2_keyevent_to_keycode_generic(ev);
364     } else {
365         keycode = gtk2_keyevent_to_keycode(ev);
366     }
367
368     switch(keycode) {
369     case 0x00:
370         /* sent when leaving window: reset the modifiers state */
371         reset_keys();
372         return;
373     case 0x2a:                          /* Left Shift */
374     case 0x36:                          /* Right Shift */
375     case 0x1d:                          /* Left CTRL */
376     case 0x9d:                          /* Right CTRL */
377     case 0x38:                          /* Left ALT */
378     case 0xb8:                         /* Right ALT */
379         if (ev->type == GDK_KEY_RELEASE)
380             modifiers_state[keycode] = 0;
381         else
382             modifiers_state[keycode] = 1;
383         break;
384     case 0x45: /* num lock */
385     case 0x3a: /* caps lock */
386         /* GTK does send the key up event, so we dont generate it */
387         /*kbd_put_keycode(keycode);
388         kbd_put_keycode(keycode | 0x80);
389         return;*/
390         break;
391     }
392
393     /* now send the key code */
394     if (keycode & 0x80)
395         kbd_put_keycode(0xe0);
396     if (ev->type == GDK_KEY_RELEASE)
397         kbd_put_keycode(keycode | 0x80);
398     else
399         kbd_put_keycode(keycode & 0x7f);
400 }
401
402 static void gtk2_update_caption(void)
403 {
404     char buf[1024];
405     strcpy(buf, "QEMU Gtk");
406     if (!vm_running) {
407         strcat(buf, " [Stopped]");
408     }
409     if (gui_grab) {
410         strcat(buf, " - Press Ctrl-Alt to exit grab");
411     }
412     gtk_window_set_title(GTK_WINDOW(window), buf);
413 }
414
415 /* what a nasty hack. this should be a part of the GDK, not external!!! */
416 #include "gdk_set_window_pointer.c"
417
418 static void gtk2_grab_start(void)
419 {
420     gint y;
421     guint events;
422     GdkModifierType state; /* dummy var */
423     GtkWidget * grab;
424     if (gui_fullscreen) /* make sure grab is on correct x window */
425         grab = window;
426     else
427         grab = event_port;
428 if (gui_rgrab || gui_fullscreen)
429 {
430     events = GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_SCROLL_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK;
431     y = gdk_pointer_grab(grab->window, TRUE, events, grab->window, invisible_cursor, GDK_CURRENT_TIME);
432     if (y)
433         printf("GTK Warning - pointer grab failed!\n");
434     y = gdk_keyboard_grab(grab->window, TRUE, GDK_CURRENT_TIME);
435     if (y)
436         printf("GTK Warning - keyboard grab failed!\n");
437 }
438     /* do a dummy read to avoid moving mouse - set ox and oy to stay in sync */
439     gdk_window_get_pointer(event_port->window, &ox, &oy, &state);
440     gui_grab = 1;
441     gtk2_update_caption();
442 }
443
444 static void gtk2_grab_end(void)
445 {
446     GtkWidget * grab;
447     if (gui_fullscreen)
448         grab = window;
449     else
450         grab = event_port;
451 if (gui_rgrab || gui_fullscreen)
452 {
453     gdk_pointer_ungrab(GDK_CURRENT_TIME);
454     gdk_keyboard_ungrab(GDK_CURRENT_TIME);
455     gdk_window_set_pointer(grab->window, win_x, win_y);
456 }
457     gui_grab = 0;
458     gtk2_update_caption();
459 }
460
461 static gboolean gtk2_send_mouse_event(GtkWidget *wid, GdkEvent *ev)
462 {
463     int x, y, dx, dy, dz, state, buttons;
464     GtkWidget * grab;
465     if (gui_fullscreen) /* make sure grab is on correct x window */
466         grab = window;
467     else
468         grab = event_port;
469
470     if (gui_fullscreen && wid == event_port) return FALSE;
471     if (!gui_fullscreen && wid == window) return FALSE;
472     if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS)
473         return TRUE; /* double or triple click - superflurious - ignore */
474
475     if (gui_grab)
476     {
477
478     if (ev->type == GDK_MOTION_NOTIFY && ev->motion.is_hint)
479     {
480         gdk_window_get_pointer(ev->motion.window, &x, &y, (GdkModifierType*)&state);
481     }
482     else
483     {
484         x = ev->motion.x;
485         y = ev->motion.y;
486         /* scroll.state occupies a different position in the union */
487         if (ev->type == GDK_SCROLL)
488         state = ev->scroll.state;
489         else
490         state = ev->motion.state;
491     }
492
493     dx = x - ox;
494     dy = y - oy;
495     // prevent infinite looping - 2.6.X
496     if ((ev->type == GDK_MOTION_NOTIFY) && (dx == 0) && (dy == 0)) return TRUE;
497     dz = 0;
498     ox = x;
499     oy = y;
500
501     buttons = 0;
502     if ((state & GDK_BUTTON1_MASK))
503         buttons |= MOUSE_EVENT_LBUTTON;
504     if ((state & GDK_BUTTON3_MASK))
505         buttons |= MOUSE_EVENT_RBUTTON;
506     if ((state & GDK_BUTTON2_MASK))
507         buttons |= MOUSE_EVENT_MBUTTON;
508
509     if (ev->type == GDK_BUTTON_PRESS)
510     {
511         if (ev->button.button == 1)
512             buttons |= MOUSE_EVENT_LBUTTON;
513         if (ev->button.button == 3)
514             buttons |= MOUSE_EVENT_RBUTTON;
515         if (ev->button.button == 2)
516             buttons |= MOUSE_EVENT_MBUTTON;
517     }
518     else if (ev->type == GDK_BUTTON_RELEASE)
519     {
520     /* not sure if this is really necessary, but just to be on the safe side **
521     ** reset qemu's mask so that a button thats being released will be shown **
522     * missing from the mask (which lets the guest know the button was relased */
523         buttons = 0;
524
525         if ((state & GDK_BUTTON1_MASK) && ev->button.button != 1)
526             buttons |= MOUSE_EVENT_LBUTTON;
527         if ((state & GDK_BUTTON3_MASK) && ev->button.button != 3)
528             buttons |= MOUSE_EVENT_RBUTTON;
529         if ((state & GDK_BUTTON2_MASK) && ev->button.button != 2)
530             buttons |= MOUSE_EVENT_MBUTTON;
531     }
532     else if (ev->type == GDK_SCROLL)
533     {
534         /* test wheel - copied from Sebastien Bechet's gtk.c */
535         if (ev->scroll.direction == GDK_SCROLL_UP)
536             dz--;
537         if (ev->scroll.direction == GDK_SCROLL_DOWN)
538             dz++;
539     }
540
541     if ((ev->type == GDK_MOTION_NOTIFY) && (gui_rgrab || gui_fullscreen))
542     {
543         /* wrap the x,y coordinates back onto the window */
544         if (ev->motion.x <= (cw/4))
545             x = ((3*cw/4)-1);
546         if (ev->motion.y <= (ch/4))
547             y = ((3*ch/4)-1);
548         if (ev->motion.x >= (3*cw/4))
549             x = (cw/4)+1;
550         if (ev->motion.y >= (3*ch/4))
551             y = (ch/4)+1;
552
553         /* make internal mouse move invisible */
554         ox = x;
555         oy = y;
556
557         gdk_window_set_pointer(grab->window, (gint)x, (gint)y);
558     }
559
560     kbd_mouse_event(dx, dy, dz, buttons);
561
562     }
563     else
564     {
565
566     if (ev->type == GDK_BUTTON_PRESS && ev->button.button == 1)
567     {
568         /* start grabbing all events */
569         gtk2_grab_start();
570     }
571
572     }
573     return TRUE;
574 }
575
576 static void toggle_full_screen(DisplayState *ds)
577 {
578     gui_fullscreen = !gui_fullscreen;
579     gtk2_resize(ds, image->width, image->height);
580     if (gui_fullscreen) {
581         gui_saved_grab = gui_grab;
582         gtk2_grab_start();
583         gtk_window_get_position(GTK_WINDOW(window), &win_x, &win_y);
584         gdk_window_move_resize(window->window, 0, 0, ds->width, ds->height);
585         gtk_widget_hide(box);
586         fullscreen_switch(win_x, win_y, ds->width, ds->height);
587     } else {
588         fullscreen_reset();
589         gdk_window_move_resize(window->window, win_x, win_y, win_w, win_h);
590         gui_fullscreen = !gui_fullscreen;
591         if (!gui_saved_grab)
592             gtk2_grab_end();
593         gui_fullscreen = !gui_fullscreen;
594         gtk_widget_show(box);
595     }
596     vga_invalidate_display();
597     vga_update_display();
598 }
599
600 static gboolean gtk2_key_press(GtkWidget *wid, GdkEventKey *ev, DisplayState *ds)
601 {
602         int mod_state, internal_key = 0;
603             if (ev->type == GDK_KEY_PRESS) {
604                 mod_state = (gtk2_GetModState(ev) & (int)gui_grab_code) == (int)gui_grab_code;
605                 gui_key_modifier_pressed = mod_state;
606                 if (gui_key_modifier_pressed) {
607                     int keycode;
608                     internal_key = 1;
609                     keycode = gtk2_keyevent_to_keycode(ev);
610                     switch(keycode) {
611                     case 0x21: /* 'f' key on US keyboard */
612                         toggle_full_screen(ds);
613                         gui_keysym = 1;
614                         break;
615                     case 0x02 ... 0x0a: /* '1' to '9' keys */ 
616                         console_select(keycode - 0x02);
617                         if (is_active_console(vga_console)) {
618                             /* tell the vga console to redisplay itself */
619                             vga_invalidate_display();
620                         } else {
621                             /* display grab if going to a text console */
622                             if (gui_grab)
623                                 gtk2_grab_end();
624                         }
625                         gui_keysym = 1;
626                         break;
627                     default:
628                         break;
629                     }
630                 } else if (!is_active_console(vga_console)) {
631                     int keysym;
632                     keysym = 0;
633                     if (ev->state & GDK_CONTROL_MASK) {
634                         switch(ev->keyval) {
635                         case GDK_Up: keysym = QEMU_KEY_CTRL_UP; break;
636                         case GDK_Down: keysym = QEMU_KEY_CTRL_DOWN; break;
637                         case GDK_Left: keysym = QEMU_KEY_CTRL_LEFT; break;
638                         case GDK_Right: keysym = QEMU_KEY_CTRL_RIGHT; break;
639                         case GDK_Home: keysym = QEMU_KEY_CTRL_HOME; break;
640                         case GDK_End: keysym = QEMU_KEY_CTRL_END; break;
641                         case GDK_Page_Up: keysym = QEMU_KEY_CTRL_PAGEUP; break;
642                         case GDK_Page_Down: keysym = QEMU_KEY_CTRL_PAGEDOWN; break;
643                         default: break;
644                         }
645                     } else {
646                         switch(ev->keyval) {
647                         case GDK_Up: keysym = QEMU_KEY_UP; break;
648                         case GDK_Down: keysym = QEMU_KEY_DOWN; break;
649                         case GDK_Left: keysym = QEMU_KEY_LEFT; break;
650                         case GDK_Right: keysym = QEMU_KEY_RIGHT; break;
651                         case GDK_Home: keysym = QEMU_KEY_HOME; break;
652                         case GDK_End: keysym = QEMU_KEY_END; break;
653                         case GDK_Page_Up: keysym = QEMU_KEY_PAGEUP; break;
654                         case GDK_Page_Down: keysym = QEMU_KEY_PAGEDOWN; break;
655                         case GDK_BackSpace: keysym = QEMU_KEY_BACKSPACE; break;
656                         case GDK_Delete: keysym = QEMU_KEY_DELETE; break;
657                         default: break;
658                         }
659                     }
660                     if (keysym) {
661                         kbd_put_keysym(keysym);
662                     } /*else if (ev->key.keysym.unicode != 0) {
663                         kbd_put_keysym(ev->key.keysym.unicode);
664                     }*/
665                 }
666             } else if (ev->type == GDK_KEY_RELEASE) {
667                 mod_state = (gtk2_GetModState(ev) & gui_grab_code);
668                 if (!mod_state) {
669                     if (gui_key_modifier_pressed) {
670                         if (gui_keysym == 0) {
671                             /* exit/enter grab if pressing Ctrl-Alt */
672                             if (!gui_grab)
673                                 gtk2_grab_start();
674                             else
675                                 gtk2_grab_end();
676                             /* SDL does not send back all the
677                                modifiers key, so we must correct it */
678                             reset_keys();
679                             return TRUE;
680                         }
681                         gui_key_modifier_pressed = 0;
682                         gui_keysym = 0;
683                         internal_key = 1;
684                     }
685                 }
686             }
687             if (is_active_console(vga_console) && !internal_key) 
688                 gtk2_process_key(ev);
689             else if (internal_key && ev->type == GDK_KEY_RELEASE)
690             {
691                 modifiers_state[0x38] = 0;
692                 modifiers_state[0x1d] = 0;
693                 kbd_put_keycode(0x38 | 0x80);
694                 kbd_put_keycode(0x1d | 0x80);
695             }
696             else if (internal_key && ev->type == GDK_KEY_PRESS)
697             {
698                 modifiers_state[0x38] = 1;
699                 modifiers_state[0x1d] = 1;
700             }
701         return TRUE;
702 }
703
704 static void gtk2_refresh(DisplayState *ds)
705 {
706     if (last_vm_running != vm_running) {
707         last_vm_running = vm_running;
708         gtk2_update_caption();
709     }
710     if (ds->data != image->mem)
711     {
712         ds->data = image->mem;
713     }
714
715     if (is_active_console(vga_console))                                         
716         vga_update_display();                                                   
717     while (gtk_events_pending())
718         gtk_main_iteration();
719 }
720
721 static void gtk2_cleanup(void) 
722 {
723     if (gtk_main_level() != 0)
724         gtk_main_quit();
725     fullscreen_cleanup();
726 }
727
728 static gboolean gtk2_deletewin(void)
729 {
730     /* signal qemu that its time to shut itself off - this is the place that we hook to trap attempts to close the main qemu window */
731     qemu_system_shutdown_request();
732     return FALSE;
733     return TRUE; /* dont close the window right away! give qemu time to think */
734 }
735
736 static void gtk2_destroy(void)
737 {
738     /* ideally we would call a hook here so qemu could clean itself up */
739     gtk2_cleanup();
740 }
741
742 GtkWidget * gui_menu_add(const gchar * name)
743 {
744     GtkWidget *menu, *menu_name;
745     menu = gtk_menu_new();
746     menu_name = gtk_menu_item_new_with_label(name);
747     gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menu_name);
748     gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_name), menu);
749     gtk_widget_show(menu_name);
750     return menu;
751 }
752
753 GtkWidget * gui_menuitem_add(GtkWidget * menu, const gchar * name, void (*item_handler)(void))
754 {
755     GtkWidget *menu_item;
756     menu_item = gtk_menu_item_new_with_label(name);
757     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
758     g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(item_handler), NULL);
759     gtk_widget_show(menu_item);
760     return menu_item;
761 }
762
763 GtkWidget * gui_menusep_add(GtkWidget * menu)
764 {
765     GtkWidget *menu_item;
766     menu_item = gtk_menu_item_new();
767     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
768     gtk_widget_show(menu_item);
769     return menu_item;
770 }
771
772 GtkWidget * gui_submenu_add(GtkWidget * menu, const gchar * name)
773 {
774     GtkWidget *submenu, *menu_name;
775     submenu = gtk_menu_new();
776     menu_name = gtk_menu_item_new_with_label(name);
777     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_name);
778     gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_name), submenu);
779     gtk_widget_show(menu_name);
780     return submenu;
781 }
782
783 void base_vc_switch(int i)
784 {
785         console_select(i);
786         if (is_active_console(vga_console)) {
787             /* tell the vga console to redisplay itself */
788             vga_invalidate_display();
789         } else {
790             /* display grab if going to a text console */
791             if (gui_grab)
792                 gtk2_grab_end();
793         }
794 }
795 void vc_guest(void) { base_vc_switch(0); }
796 void vc_monitor(void) { base_vc_switch(1); }
797 void vc_serial(void) { base_vc_switch(2); }
798 void vc_para(void) { base_vc_switch(3); }
799 void nop(void) {}
800
801 void gtk2_menu_init(void)
802 {
803         GtkWidget * menu;
804         menu = gui_menu_add("Monitor");
805         gui_menuitem_add(menu, "Reset", qemu_system_reset_request);
806         gui_menuitem_add(menu, "Quit", qemu_system_shutdown_request);
807         menu = gui_menu_add("Virtual Console");
808         menu = gui_submenu_add(menu, "Switch to");
809         gui_menuitem_add(menu, "Guest", vc_guest);
810         gui_menuitem_add(menu, "Monitor", vc_monitor);
811         gui_menuitem_add(menu, "Serial", vc_serial);
812         gui_menuitem_add(menu, "Parallel", vc_para);
813         menu = gui_menu_add("Help");
814         gui_menuitem_add(menu, "About", nop);
815 }
816
817 static int gargc=0;
818 static char ** gargv=NULL;
819 void gtk2_display_init(DisplayState *ds, int full_screen)
820 {
821     int events;
822
823 #if defined(__APPLE__)
824     /* always use generic keymaps */
825     if (!keyboard_layout)
826         keyboard_layout = "en-us";
827 #endif
828     if(keyboard_layout) {
829         kbd_layout = init_keyboard_layout(keyboard_layout);
830         if (!kbd_layout)
831             exit(1);
832     }
833
834 /* note - this strips the GTK-specific args after the main program is done with them */
835     if (!gtk_init_check (&gargc,&gargv))
836     {
837         fprintf(stderr, "Could not load GTK\n");
838         exit(0);
839     }
840     gui_rgrab = 0;
841     fullscreen_init();
842
843 /* note: adding GDK_DRAG_* and GDK_DROP_* would provide a mechanism for supporting drag and drop between host and guest */
844     events = GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK | GDK_SCROLL_MASK | GDK_STRUCTURE_MASK;
845
846     window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
847     swindow = gtk_scrolled_window_new(NULL,NULL);
848     event_port = gtk_event_box_new();
849     menubar = gtk_menu_bar_new();
850     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow), GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS);
851     box = gtk_vbox_new(FALSE, 0);
852     gtk_container_add(GTK_CONTAINER(window), box);
853     gtk_box_pack_start(GTK_BOX(box), menubar, FALSE, FALSE, 0);
854     gtk_box_pack_start(GTK_BOX(box), swindow, TRUE, TRUE, 0);
855     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(swindow), event_port);
856     gtk_widget_set_events(event_port, events);
857     gtk_window_set_default_size(GTK_WINDOW(window), 720, 420);
858     gtk_widget_set_size_request(window, 0, 0);
859     gtk_widget_set_size_request(swindow, 720, 400);
860     gtk_widget_set_size_request(event_port, 720, 400);
861     gtk_window_set_gravity(GTK_WINDOW(window), GDK_GRAVITY_STATIC);
862     gtk2_menu_init();
863
864     g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(gtk2_deletewin), NULL);
865     g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk2_destroy), NULL);
866     gtk_container_set_border_width(GTK_CONTAINER(window), 0);
867
868     g_signal_connect(G_OBJECT(window), "configure_event", G_CALLBACK(gtk2_config), NULL);
869     g_signal_connect(G_OBJECT(window), "expose_event", G_CALLBACK(gtk2_expose), NULL);
870     g_signal_connect(G_OBJECT(window), "motion_notify_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
871     g_signal_connect(G_OBJECT(window), "button_press_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
872     g_signal_connect(G_OBJECT(window), "button_release_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
873     g_signal_connect(G_OBJECT(window), "scroll_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
874     g_signal_connect(G_OBJECT(event_port), "expose_event", G_CALLBACK(gtk2_expose), NULL);
875     g_signal_connect(G_OBJECT(event_port), "motion_notify_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
876     g_signal_connect(G_OBJECT(event_port), "button_press_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
877     g_signal_connect(G_OBJECT(event_port), "button_release_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
878     g_signal_connect(G_OBJECT(event_port), "scroll_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
879     g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(gtk2_key_press), ds);
880     g_signal_connect(G_OBJECT(window), "key_release_event", G_CALLBACK(gtk2_key_press), ds);
881
882     ds->dpy_update = gtk2_update;
883     ds->dpy_resize = gtk2_resize;
884     ds->dpy_refresh = gtk2_refresh;
885
886     gchar nullpixdata[1] = { 0 };
887     GdkColor nullcolor = { 0, 0, 0, 0 };
888     GdkPixmap *invis = gdk_bitmap_create_from_data(window->window, nullpixdata, 1, 1);
889     invisible_cursor = gdk_cursor_new_from_pixmap(invis, invis, &nullcolor, &nullcolor, 0, 0);
890
891     gtk2_resize(ds, 720, 400);
892     gtk2_update_caption();
893     gui_grab = 0;
894
895     gtk_widget_show(event_port);
896     gtk_widget_show(swindow);
897     gtk_widget_show(menubar);
898     gtk_widget_show(box);
899     gtk_widget_show(window);
900     if (full_screen) {
901         gui_fullscreen = 1;
902         gui_fullscreen_initial_grab = 1;
903         gtk2_grab_start();
904     }
905 }
906
907 /* we are allowed to look at the args, but not allowed to modify them
908 with the exception that we have to remove args that are meant for us, as
909 main qemu will not recognize them */
910 void gui_checkargs(int * pargc, char *** pargv)
911 {
912     int argc = *pargc;
913     char ** argv = *pargv;
914     char ** vargv;
915     int i, j = 0;
916     vargv = malloc(argc * sizeof(char*));
917     for (i = 0; i < argc; i++)
918     {
919         if (!strcmp(argv[i], "-window-resize-on"))
920         {
921                 window_resize = 1;
922                 (*pargc)--;
923         }
924         else if (!strcmp(argv[i], "-raw-grab"))
925         {
926                 gui_rgrab = 1;
927                 (*pargc)--;
928         }
929         else
930         {
931                 vargv[j] = argv[i];
932                 j++;
933         }
934     }
935     /* so lets hide them */
936     for (i = 0; i < *pargc; i++)
937     {
938         (*pargv)[i] = vargv[i];
939     }
940     if (argc != (*pargc)) (*pargv)[*pargc] = NULL;
941     free(vargv);
942     /* save a copy so we can pass them to gtk_init() later */
943     gargc = *pargc;
944     gargv = *pargv;
945 }
946