symbian-qemu-0.9.1-12/qemu-symbian-svp/gui.c
changeset 1 2fb8b9db1c86
child 61 42fe4f76a74e
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * GUI implementation
       
     3  *
       
     4  * Copyright (c) 2009 CodeSourcery
       
     5  *
       
     6  * Permission is hereby granted, free of charge, to any person obtaining a copy
       
     7  * of this software and associated documentation files (the "Software"), to deal
       
     8  * in the Software without restriction, including without limitation the rights
       
     9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    10  * copies of the Software, and to permit persons to whom the Software is
       
    11  * furnished to do so, subject to the following conditions:
       
    12  *
       
    13  * The above copyright notice and this permission notice shall be included in
       
    14  * all copies or substantial portions of the Software.
       
    15  *
       
    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
       
    19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       
    20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       
    21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       
    22  * THE SOFTWARE.
       
    23  */
       
    24 
       
    25 #include "hw/hw.h"
       
    26 #include "sysemu.h"
       
    27 #include "stdio.h"
       
    28 #include "qemu-timer.h"
       
    29 #include "hw/gui.h"
       
    30 #include "gui_host.h"
       
    31 #include "gui_common.h"
       
    32 #include "gui_parser.h"
       
    33 #define HOST_ONLY_DEFS /* DFG: FIXME */
       
    34 #include "hw/fb_render_engine.h"
       
    35 #include "gui_png.h"
       
    36 
       
    37 #define MAX_CONSOLES 12
       
    38 
       
    39 typedef void (*button_action_t)(void *parameter);
       
    40 
       
    41 struct button_actions_s
       
    42 {
       
    43     button_action_t down;
       
    44     button_action_t up;
       
    45 };
       
    46 
       
    47 enum button_actions_e
       
    48 {
       
    49     BUTTON_ACTION_NOACTION = 0,
       
    50     BUTTON_ACTION_SENDKEY = 1,
       
    51 };
       
    52 
       
    53 typedef enum
       
    54 {
       
    55     CA_POINTERAREA,
       
    56     CA_BUTTON
       
    57 } clickarea_type;
       
    58 
       
    59 typedef struct
       
    60 {
       
    61     devid_t devid;
       
    62     int absolute;
       
    63     int grab_on_click;
       
    64     int show_cursor_while_grabbing;
       
    65     QEMUPutMouseEvent *callback;
       
    66     void *opaque;
       
    67 } pointer_area_t;
       
    68 
       
    69 typedef struct
       
    70 {
       
    71     ImageID pressed_img_id;
       
    72     enum button_actions_e actions;
       
    73     void* parameter;
       
    74 } button_t;
       
    75 
       
    76 typedef struct
       
    77 {
       
    78     gui_area_t area;
       
    79     clickarea_type type;
       
    80     int id;
       
    81 } clickable_area_t;
       
    82 
       
    83 typedef struct
       
    84 {
       
    85     /* TODO: Optimize with a geometrical index */
       
    86     clickable_area_t *areas;
       
    87     unsigned int n_areas;
       
    88     clickable_area_t *currently_grabbing; /* NULL if none */
       
    89 } clickable_map_t;
       
    90 
       
    91 typedef struct
       
    92 {
       
    93     devid_t devid;
       
    94     DisplayState ds;
       
    95     vga_hw_update_ptr update;
       
    96     vga_hw_invalidate_ptr invalidate;
       
    97     vga_hw_screen_dump_ptr screen_dump;
       
    98     /*vga_hw_text_update_ptr text_update;*/
       
    99     void *opaque;
       
   100 } ds_data_t;
       
   101 
       
   102 typedef struct
       
   103 {
       
   104     ds_data_t *ds_data;
       
   105     unsigned int n_ds;
       
   106 
       
   107     int order_priority; /* This is used to place this VT in the key sequence (i.e. skinned VTs first) */
       
   108 
       
   109     pointer_area_t *pointerareas;
       
   110     unsigned int n_pointerareas;
       
   111 
       
   112     KeyCallback key_callback;
       
   113     void *key_opaque;
       
   114 
       
   115     /* skin data */
       
   116     int has_skin;
       
   117 
       
   118     /* If has skin, the following data applies.
       
   119        Maybe all should be moved to skin_data_t.
       
   120     */
       
   121     DisplayState gui_ds; /* just for skin and host images */
       
   122 
       
   123 
       
   124     void *background_buffer;
       
   125     unsigned int background_row_size;
       
   126     render_data *rdata;
       
   127     int full_update;
       
   128 
       
   129     gui_image_t *images;
       
   130     unsigned int n_images;
       
   131     clickable_map_t clickable_map;
       
   132     button_t *buttons;
       
   133     unsigned int n_buttons;
       
   134 
       
   135 } vt_t;
       
   136 
       
   137 enum gui_input_state_t
       
   138 {
       
   139     INPUT_STATE_GUI_UNLOADED, /* Compatible with old (gui-less) machines */
       
   140     INPUT_STATE_GUI_LOADED
       
   141 };
       
   142 
       
   143 typedef struct
       
   144 {
       
   145     void (*gui_notify_toggle_fullscreen)(void);
       
   146     void (*gui_notify_toggle_grabmode)(void);
       
   147     void (*gui_notify_mouse_motion)(int dx, int dy, int dz, int x, int y, int state);
       
   148     void (*gui_notify_mouse_button)(int dz, int x, int y, int state);
       
   149     void (*gui_notify_mouse_warp)(int x, int y, int on);
       
   150     void (*gui_notify_new_guest_cursor)(void);
       
   151     void (*gui_notify_input_focus_lost)(void);
       
   152     void (*gui_notify_app_focus)(int gain);
       
   153 } gui_input_table_t;
       
   154 
       
   155 struct gui_data_t
       
   156 {
       
   157     gui_host_callbacks_t host_callbacks;
       
   158     vt_t vts[MAX_CONSOLES];
       
   159     unsigned int n_vts;
       
   160     vt_t *current_vt;
       
   161     VtID ordered_vts[MAX_CONSOLES]; /* Vts sorted by order_priority */
       
   162     screen_data_t screen_data;
       
   163 
       
   164     struct QEMUTimer *gui_timer;
       
   165     uint64_t gui_timer_interval;
       
   166     int idle; /* there is nothing to update (window invisible), set by vnc/sdl */
       
   167 
       
   168     int updating; /* to prevent recursion */
       
   169 
       
   170     /* Input stuff */
       
   171     KeyCallback dev_key_callback;
       
   172     void *dev_key_opaque;
       
   173 
       
   174     int gui_fullscreen;
       
   175 
       
   176     const gui_input_table_t* input_table;
       
   177     int guest_cursor;
       
   178     int guest_x;
       
   179     int guest_y;
       
   180     int last_vm_running;
       
   181     struct {
       
   182         int absolute_enabled;
       
   183         int gui_grab; /* if true, all keyboard/mouse events are grabbed */
       
   184         int gui_saved_grab;
       
   185         int gui_fullscreen_initial_grab;
       
   186     } unloaded_state_data;
       
   187 
       
   188     int loaded;
       
   189 };
       
   190 
       
   191 static struct gui_data_t* gui_data = NULL;
       
   192 /*******************************************/
       
   193 
       
   194 
       
   195 /* Internal Functions ==================== */
       
   196 static parse_result_t load_gui_xml(const char* xml_file);
       
   197 static void index_map(clickable_map_t *map);
       
   198 static void initialize_display_areas(VtID vtid);
       
   199 static void destroy_clickable_map(clickable_map_t *map);
       
   200 static void destroy_images(VtID vtid);
       
   201 static void gui_update_guest_display(vt_t *vt);
       
   202 static void init_background(VtID vtid);
       
   203 static void gui_set_input_state(enum gui_input_state_t input_state);
       
   204 static void gui_update_caption(void);
       
   205 static void gui_update_ds_data(DisplayState *ds, int in_skinned_vt);
       
   206 
       
   207 static void gui_loaded_grab_end(void);
       
   208 static void gui_update_timer(int64_t ticks);
       
   209 
       
   210 /* ======================================= */
       
   211 
       
   212 int ds_get_width(const DisplayState *ds)
       
   213 {
       
   214     return ds->width;
       
   215 }
       
   216 
       
   217 int ds_get_height(const DisplayState *ds)
       
   218 {
       
   219     return ds->height;
       
   220 }
       
   221 
       
   222 int ds_get_bits_per_pixel(const DisplayState *ds)
       
   223 {
       
   224     return ds->depth;
       
   225 }
       
   226 
       
   227 int ds_get_bgr(const DisplayState *ds)
       
   228 {
       
   229     return ds->bgr;
       
   230 }
       
   231 
       
   232 int ds_get_linesize(const DisplayState *ds)
       
   233 {
       
   234     return ds->linesize;
       
   235 }
       
   236 
       
   237 uint8_t *ds_get_data(const DisplayState *ds)
       
   238 {
       
   239     return ds->data;
       
   240 }
       
   241 
       
   242 static inline int vt_enabled(void)
       
   243 {
       
   244     return gui_data->current_vt != NULL;
       
   245 }
       
   246 
       
   247 static inline VtID current_vt_id(void)
       
   248 {
       
   249     return gui_data->current_vt - &gui_data->vts[0];
       
   250 }
       
   251 
       
   252 static inline int is_current_vt(VtID vtid)
       
   253 {
       
   254     return gui_data->current_vt == &gui_data->vts[vtid];
       
   255 }
       
   256 
       
   257 static inline void invalidate_ds(const ds_data_t* ds_data)
       
   258 {
       
   259     if (ds_data->invalidate != NULL)
       
   260         ds_data->invalidate(ds_data->opaque);
       
   261 }
       
   262 
       
   263 static inline void update_ds(const ds_data_t* ds_data)
       
   264 {
       
   265     if (ds_data->update != NULL)
       
   266         ds_data->update(ds_data->opaque);
       
   267 }
       
   268 
       
   269 static inline int get_vt_width(const vt_t *vt)
       
   270 {
       
   271     if (vt->has_skin)
       
   272         return GET_GUI_AREA_WIDTH(&vt->images[DEF_BACKGROUND_IMAGE].area);
       
   273     else
       
   274         return vt->ds_data[0].ds.width;
       
   275 }
       
   276 
       
   277 static inline int get_vt_height(const vt_t *vt)
       
   278 {
       
   279     if (vt->has_skin)
       
   280         return GET_GUI_AREA_HEIGHT(&vt->images[DEF_BACKGROUND_IMAGE].area);
       
   281     else
       
   282         return vt->ds_data[0].ds.height;
       
   283 }
       
   284 
       
   285 void dpy_update(DisplayState *s, int x, int y, int w, int h)
       
   286 {
       
   287     s->dpy_update(s, x, y, w, h);
       
   288 }
       
   289 
       
   290 void dpy_cursor(DisplayState *s, int x, int y)
       
   291 {
       
   292     if (s->dpy_text_cursor)
       
   293         s->dpy_text_cursor(s, x, y);
       
   294 }
       
   295 
       
   296 static int accepts_kbd(const vt_t *vt)
       
   297 {
       
   298     return (vt->key_callback != NULL);
       
   299 #if 0
       
   300     DFG FIXME: manage multiple text consoles
       
   301     int accepts = 0;
       
   302 
       
   303     if (vt->n_ds_data > 0) {
       
   304         int vtid = 0;
       
   305         do {
       
   306             accepts = (vt->ds_data[vtid++]->);
       
   307         } while (!accepts && vtid < vt->n_ds_data);
       
   308     }
       
   309 
       
   310     return accepts;
       
   311 #endif
       
   312 }
       
   313 
       
   314 void gui_init(gui_host_callbacks_t* callbacks)
       
   315 {
       
   316     gui_data = (struct gui_data_t*)qemu_mallocz(sizeof(struct gui_data_t));
       
   317 
       
   318     gui_set_input_state(INPUT_STATE_GUI_UNLOADED);
       
   319     if (callbacks != NULL) {
       
   320         gui_data->host_callbacks = *callbacks;
       
   321         gui_data->host_callbacks.set_screen_size(640, 480, 0);
       
   322         gui_data->host_callbacks.get_screen_data(&gui_data->screen_data);
       
   323     }
       
   324 
       
   325     gui_update_caption();
       
   326 }
       
   327 
       
   328 void gui_destroy(void)
       
   329 {
       
   330     if (gui_data != NULL) {
       
   331         if (gui_data->loaded)
       
   332             gui_unload();
       
   333         qemu_free(gui_data);
       
   334         gui_data = NULL;
       
   335     }
       
   336 }
       
   337 
       
   338 int gui_load(const char *xml_file)
       
   339 {
       
   340     parse_result_t res;
       
   341     int vt;
       
   342     
       
   343     res = load_gui_xml(xml_file);
       
   344     if (res == PARSE_OK) {
       
   345         gui_data->loaded = 1;
       
   346 
       
   347         for (vt = 0; vt < gui_data->n_vts; vt++) {
       
   348             index_map(&gui_data->vts[vt].clickable_map);
       
   349             if (gui_data->vts[vt].has_skin) {
       
   350                 gui_data->vts[vt].rdata = create_render_data();
       
   351                 init_background(vt);
       
   352                 gui_show_image(vt, DEF_BACKGROUND_IMAGE);
       
   353             }
       
   354             initialize_display_areas(vt);
       
   355         }
       
   356         gui_set_input_state(INPUT_STATE_GUI_LOADED);
       
   357         gui_data->current_vt = &gui_data->vts[0];
       
   358         /*gui_notify_console_select(0); Done in vl.c */
       
   359     } else {
       
   360         if (parsing_location_error() != NULL)
       
   361             fprintf(stderr, "GUI parser error %d at %s\n", res, parsing_location_error());
       
   362     }
       
   363 
       
   364     return res == PARSE_OK;
       
   365 }
       
   366 
       
   367 void gui_unload(void)
       
   368 {
       
   369     int vt;
       
   370     if (gui_data->loaded) {
       
   371         for (vt = 0; vt < gui_data->n_vts; vt++) {
       
   372             destroy_images(vt);
       
   373             destroy_clickable_map(&gui_data->vts[vt].clickable_map);
       
   374             destroy_render_data(gui_data->vts[vt].rdata);
       
   375             qemu_free(gui_data->vts[vt].background_buffer);
       
   376             qemu_free(gui_data->vts[vt].ds_data);
       
   377         }
       
   378         gui_set_input_state(INPUT_STATE_GUI_UNLOADED);
       
   379         gui_data->loaded = 0;
       
   380     }
       
   381 }
       
   382 
       
   383 int gui_needs_timer(void)
       
   384 {
       
   385     return (gui_data->host_callbacks.process_events != NULL);
       
   386 }
       
   387 
       
   388 void gui_set_timer(struct QEMUTimer *timer)
       
   389 {
       
   390     gui_data->gui_timer = timer;
       
   391 }
       
   392 
       
   393 static void init_background(VtID vtid)
       
   394 {
       
   395     const int background_width = GET_GUI_AREA_WIDTH(&gui_data->vts[vtid].images[DEF_BACKGROUND_IMAGE].area);
       
   396     const int background_height = GET_GUI_AREA_HEIGHT(&gui_data->vts[vtid].images[DEF_BACKGROUND_IMAGE].area);
       
   397 
       
   398     gui_data->vts[vtid].gui_ds.width = background_width;
       
   399     gui_data->vts[vtid].gui_ds.height = background_height;
       
   400     gui_data->host_callbacks.init_ds(&gui_data->vts[vtid].gui_ds);
       
   401     gui_update_ds_data(&gui_data->vts[vtid].gui_ds, 1);
       
   402 
       
   403     gui_data->vts[vtid].background_row_size = background_width * 4;
       
   404 
       
   405     gui_data->vts[vtid].background_buffer = (void*)qemu_malloc(
       
   406         gui_data->vts[vtid].background_row_size * background_height);
       
   407 
       
   408     set_fb_base_from_host(gui_data->vts[vtid].rdata, 
       
   409                           gui_data->vts[vtid].background_buffer);
       
   410 
       
   411     set_cols(gui_data->vts[vtid].rdata, background_width);
       
   412     set_rows(gui_data->vts[vtid].rdata, background_height);
       
   413 
       
   414     /* FIXME: these data should be taken from the image_data,
       
   415        rather than hardcode this here. */
       
   416         /*set_pixel_order(gui_data->rdata, PO_BE);*/
       
   417         set_byte_order(gui_data->vts[vtid].rdata, BO_LE);
       
   418         set_color_order(gui_data->vts[vtid].rdata, CO_RGB);
       
   419         set_src_bpp(gui_data->vts[vtid].rdata, BPP_SRC_32);
       
   420     /* **** */
       
   421 
       
   422     gui_update_guest_display(&gui_data->vts[vtid]);
       
   423 }
       
   424 
       
   425 static void gui_update_guest_display(vt_t *vt)
       
   426 {
       
   427     if (!nographic && vt->gui_ds.depth != 0) {
       
   428         render(&vt->gui_ds, vt->rdata, vt->full_update);
       
   429         vt->full_update = 0;
       
   430     }
       
   431 }
       
   432 
       
   433 enum what_buffer_t {
       
   434     FROM_BG_BUFFER,
       
   435     FROM_DEF_BG_IMAGE
       
   436 };
       
   437 
       
   438 static inline char* calc_bg_area_address(VtID vtid, const gui_area_t *area, enum what_buffer_t what_buffer)
       
   439 {
       
   440     return (what_buffer == FROM_BG_BUFFER ? 
       
   441                 (char*)gui_data->vts[vtid].background_buffer :
       
   442                 (char*)gui_data->vts[vtid].images[DEF_BACKGROUND_IMAGE].image) +
       
   443         area->y0 * gui_data->vts[vtid].background_row_size +
       
   444         area->x0 * 4;
       
   445 }
       
   446 
       
   447 static void paint_rectangle(VtID vtid, gui_area_t *area, const void* source, int src_row_size)
       
   448 {
       
   449     const int area_height = GET_GUI_AREA_HEIGHT(area);
       
   450     const int area_row_size = src_row_size > 0 ? src_row_size : GET_GUI_AREA_WIDTH(area) * 4;
       
   451     char* dest = calc_bg_area_address(vtid, area, FROM_BG_BUFFER);
       
   452     const char* src = (const char*)source;
       
   453     int y = 0;
       
   454 
       
   455     for (y=0; y < area_height; y++) {
       
   456         memcpy(dest, src, area_row_size);
       
   457         dest += gui_data->vts[vtid].background_row_size;
       
   458         src += area_row_size;
       
   459     }
       
   460 }
       
   461 
       
   462 void gui_show_image(VtID vtid, ImageID id)
       
   463 {
       
   464     if (id == DEF_BACKGROUND_IMAGE) {
       
   465         /* background is the whole DS */
       
   466         memcpy(gui_data->vts[vtid].background_buffer,
       
   467                gui_data->vts[vtid].images[id].image, 
       
   468                    gui_data->vts[vtid].background_row_size *
       
   469                    GET_GUI_AREA_HEIGHT(&gui_data->vts[vtid].images[id].area));
       
   470 
       
   471     } else {
       
   472         paint_rectangle(vtid,
       
   473                         &gui_data->vts[vtid].images[id].area, 
       
   474                         gui_data->vts[vtid].images[id].image, 
       
   475                         0);
       
   476     }
       
   477 
       
   478     gui_data->vts[vtid].images[id].visible = 1;
       
   479 
       
   480     gui_data->vts[vtid].full_update = 1;    /* DFG TODO: IMPROVE! */
       
   481 }
       
   482 
       
   483 void gui_hide_image(VtID vtid, ImageID id)
       
   484 {
       
   485     /* restore the background there */
       
   486 
       
   487     paint_rectangle(vtid,
       
   488                     &gui_data->vts[vtid].images[id].area, 
       
   489                     calc_bg_area_address(vtid,
       
   490                                          &gui_data->vts[vtid].images[id].area,
       
   491                                          FROM_DEF_BG_IMAGE),
       
   492                     gui_data->vts[vtid].background_row_size);
       
   493 
       
   494     gui_data->vts[vtid].images[id].visible = 0;
       
   495 
       
   496     gui_data->vts[vtid].full_update = 1;    /* DFG TODO: IMPROVE! */
       
   497 }
       
   498 
       
   499 int gui_register_mouse_event_handler(QEMUPutMouseEvent *func,
       
   500                                      void *opaque, int absolute,
       
   501                                      const char *devname)
       
   502 {
       
   503     if (gui_data->loaded) {
       
   504         int found = 0;
       
   505         VtID vtid = 0;
       
   506         int parea;
       
   507 
       
   508         while (!found && vtid < gui_data->n_vts) {
       
   509             parea = 0;
       
   510             while (!found && parea < gui_data->vts[vtid].n_pointerareas) {
       
   511                 found = (strcmp(gui_data->vts[vtid].pointerareas[parea].devid, devname) == 0);
       
   512                 if (!found)
       
   513                     parea++;
       
   514             }
       
   515             if (!found)
       
   516                 vtid++;
       
   517         }
       
   518 
       
   519         if (found) {
       
   520             gui_data->vts[vtid].pointerareas[parea].callback = func;
       
   521             gui_data->vts[vtid].pointerareas[parea].absolute = absolute;
       
   522             gui_data->vts[vtid].pointerareas[parea].opaque = opaque;
       
   523         } else {
       
   524             fprintf(stderr, "Warning: pointer device %s not accepted by the gui. Device ignored.\n", devname);
       
   525         }
       
   526 
       
   527         return found;
       
   528     } else {
       
   529         qemu_add_mouse_event_handler(func, opaque, absolute, devname);
       
   530         return 1;
       
   531     }
       
   532 }
       
   533 
       
   534 void gui_set_paint_callbacks(DisplayState *ds,
       
   535                              vga_hw_update_ptr update,
       
   536                              vga_hw_invalidate_ptr invalidate,
       
   537                              vga_hw_screen_dump_ptr screen_dump,
       
   538                              void *opaque)
       
   539 {
       
   540     ds_data_t * const ds_data = &gui_data->vts[ds->vtid].ds_data[ds->dispid];
       
   541     ds_data->update = update;
       
   542     ds_data->invalidate = invalidate;
       
   543     ds_data->screen_dump = screen_dump;
       
   544     ds_data->opaque = opaque;
       
   545 }
       
   546 
       
   547 DisplayState *gui_get_graphic_console(const char *devname,
       
   548                                       vga_hw_update_ptr update,
       
   549                                       vga_hw_invalidate_ptr invalidate,
       
   550                                       vga_hw_screen_dump_ptr screen_dump,
       
   551                                       void *opaque)
       
   552 {
       
   553     DisplayState *ret = NULL;
       
   554 
       
   555     if (gui_data->loaded && devname != NULL) {
       
   556         int found = 0;
       
   557         VtID vtid = 0;
       
   558         DisplayID dispid;
       
   559 
       
   560         while (!found && vtid < gui_data->n_vts) {
       
   561             dispid = 0;
       
   562             while (!found && dispid < gui_data->vts[vtid].n_ds) {
       
   563                 found = (strcmp(gui_data->vts[vtid].ds_data[dispid].devid, devname) == 0);
       
   564                 if (!found)
       
   565                     dispid++;
       
   566             }
       
   567             if (!found)
       
   568                 vtid++;
       
   569         }
       
   570 
       
   571         if (found)
       
   572             ret = &gui_data->vts[vtid].ds_data[dispid].ds;
       
   573         else
       
   574             fprintf(stderr, "Warning: frame buffer '%s' not found in the GUI, assigning a skinless VT to it.\n", devname);
       
   575     }
       
   576 
       
   577     if (ret == NULL)  /* Allocate a new (skinless) VT */
       
   578         ret = gui_new_vt(SKINLESS_GRAPHIC_VT_PRIORITY_ORDER);
       
   579 
       
   580     if (ret != NULL)
       
   581         gui_set_paint_callbacks(ret, update, invalidate, screen_dump, opaque);
       
   582 
       
   583     return ret;
       
   584 }
       
   585 
       
   586 void gui_register_dev_key_callback(KeyCallback cb, void *opaque)
       
   587 {
       
   588     gui_data->dev_key_callback = cb;
       
   589     gui_data->dev_key_opaque = opaque;
       
   590 }
       
   591 
       
   592 void gui_register_vt_key_callback(DisplayState *ds, KeyCallback cb, void *opaque)
       
   593 {
       
   594     gui_data->vts[ds->vtid].key_callback = cb;
       
   595     gui_data->vts[ds->vtid].key_opaque = opaque;
       
   596 }
       
   597 
       
   598 /* only for skinless vts */
       
   599 int gui_resize_vt(DisplayState *ds, int width, int height)
       
   600 {
       
   601     const VtID vtid = ds->vtid;
       
   602 
       
   603     if (!gui_data->vts[vtid].has_skin) {
       
   604         ds_data_t * const ds_data = &gui_data->vts[vtid].ds_data[0]; /* assume ds->dispid == 0 */
       
   605 
       
   606         if (is_current_vt(vtid)) { 
       
   607             gui_data->host_callbacks.set_screen_size(width, 
       
   608                                                      height,
       
   609                                                      gui_data->gui_fullscreen);
       
   610 
       
   611             gui_data->host_callbacks.get_screen_data(&gui_data->screen_data);
       
   612             gui_update_ds_data(&ds_data->ds, 0);
       
   613         }
       
   614 
       
   615         ds_data->ds.width = width;
       
   616         ds_data->ds.height = height;
       
   617 
       
   618         if (!gui_data->updating) {
       
   619             invalidate_ds(ds_data);
       
   620 
       
   621             if (is_current_vt(vtid))
       
   622                 update_ds(ds_data);
       
   623         }
       
   624 
       
   625         return 1;
       
   626     }
       
   627     else {
       
   628         fprintf(stderr, "Error: cannot resize a skinned gui. Specify the dimensions in the XML file.\n");
       
   629         return 0;
       
   630     }
       
   631 }
       
   632 
       
   633 static VtID insert_new_vt(int order_priority)
       
   634 {
       
   635     int position = 0;
       
   636     VtID new_vtid;
       
   637 
       
   638     while(position < gui_data->n_vts && gui_data->vts[gui_data->ordered_vts[position]].order_priority <= order_priority)
       
   639         position++;
       
   640 
       
   641     if (position < gui_data->n_vts) {
       
   642         /* insert a place, shift all the remaining elements 1 position. */
       
   643         int i;
       
   644         for (i = gui_data->n_vts; i > position; i--)
       
   645             gui_data->ordered_vts[i] = gui_data->ordered_vts[i-1];
       
   646     } /* else : new one */
       
   647 
       
   648     new_vtid = gui_data->n_vts++;
       
   649     gui_data->ordered_vts[position] = new_vtid;
       
   650     gui_data->vts[new_vtid].order_priority = order_priority;
       
   651 
       
   652     return new_vtid;
       
   653 }
       
   654 
       
   655 DisplayState *gui_new_vt(int order_priority)
       
   656 {
       
   657     int vtid = -1;
       
   658 
       
   659     if (gui_data->n_vts < MAX_CONSOLES-1) {
       
   660         /* find where to insert this according to order_priority */
       
   661         vtid = insert_new_vt(order_priority);
       
   662 
       
   663         /* allocate and initialize */
       
   664         gui_data->vts[vtid].has_skin = 0; /* redundant, but to be clear */
       
   665         gui_data->vts[vtid].n_ds = 1;
       
   666         gui_data->vts[vtid].ds_data = (ds_data_t*)qemu_mallocz(sizeof(ds_data_t)*1);
       
   667         gui_data->host_callbacks.init_ds(&gui_data->vts[vtid].ds_data[0].ds);
       
   668         gui_update_ds_data(&gui_data->vts[vtid].ds_data[0].ds, 0);
       
   669         gui_data->vts[vtid].ds_data->ds.width = 640;
       
   670         gui_data->vts[vtid].ds_data->ds.height = 480;
       
   671         gui_data->vts[vtid].ds_data->ds.vtid = vtid;
       
   672         gui_data->vts[vtid].ds_data->ds.dispid = 0;
       
   673         return &gui_data->vts[vtid].ds_data->ds;
       
   674     } else {
       
   675         fprintf(stderr, "Error: too many consoles.\n");
       
   676         return NULL;
       
   677     }
       
   678 }
       
   679 
       
   680 /************ Button Actions **************/
       
   681 static void gui_button_noaction(void *parameter)
       
   682 {
       
   683 }
       
   684 
       
   685 static void gui_button_sendkey_dn(void *parameter)
       
   686 {
       
   687     const int key = (int)(long int)parameter;
       
   688 
       
   689     gui_notify_dev_key(key);
       
   690 }
       
   691 
       
   692 static void gui_button_sendkey_up(void *parameter)
       
   693 {
       
   694     const int key = (int)(long int)parameter;
       
   695 
       
   696     gui_notify_dev_key(key | 0x80);
       
   697 }
       
   698 
       
   699 struct button_actions_s button_actions[] =
       
   700 {
       
   701     { gui_button_noaction, gui_button_noaction },
       
   702     { gui_button_sendkey_dn, gui_button_sendkey_up },
       
   703 };
       
   704 
       
   705 /************ Internal Functions Definition **************/
       
   706 
       
   707 enum AreaAdjustment
       
   708 {
       
   709     AREA_CONTAINED_OK,
       
   710     AREA_NOT_CONTAINED,
       
   711     AREA_DIMENSIONS_ADJUSTED
       
   712 };
       
   713 
       
   714 static enum AreaAdjustment adjust_area_to_bg(VtID vtid, gui_area_t *area)
       
   715 {
       
   716     enum AreaAdjustment ret = AREA_CONTAINED_OK;
       
   717 
       
   718     const int bg_width = get_vt_width(&gui_data->vts[vtid]);
       
   719     const int bg_height = get_vt_height(&gui_data->vts[vtid]);
       
   720 
       
   721     if (area->x0 > bg_width || area->y0 > bg_height)
       
   722         ret = AREA_NOT_CONTAINED;
       
   723     else {
       
   724         const int area_width = GET_GUI_AREA_WIDTH(area);
       
   725         const int area_height = GET_GUI_AREA_HEIGHT(area);
       
   726 
       
   727         if ((area->x0 + area_width) > bg_width || area_width <= 0) {
       
   728             SET_GUI_AREA_WIDTH(area, bg_width - area->x0);
       
   729             if (area_width > 0)
       
   730                 ret = AREA_DIMENSIONS_ADJUSTED;
       
   731         }
       
   732 
       
   733         if ((area->y0 + area_height) > bg_height || area_height <= 0) {
       
   734             SET_GUI_AREA_HEIGHT(area, bg_height - area->y0);
       
   735             if (area_height > 0)
       
   736                 ret = AREA_DIMENSIONS_ADJUSTED;
       
   737         }
       
   738     }
       
   739 
       
   740     return ret;
       
   741 }
       
   742 
       
   743 static void load_gui_image(VtID vtid, ImageID id, const image_node_t *image_node)
       
   744 {
       
   745     gui_data->vts[vtid].images[id].area = image_node->area;
       
   746 
       
   747     if (id == DEF_BACKGROUND_IMAGE) {
       
   748         /* Ensure x0,y0 are 0,0*/
       
   749         if (gui_data->vts[vtid].images[id].area.x0 != 0 ||
       
   750             gui_data->vts[vtid].images[id].area.y0 != 0) {
       
   751 
       
   752             fprintf(stderr, "Warning: invalid (x0,y0) for background. They should be (0,0).\n");
       
   753             gui_data->vts[vtid].images[id].area.x0 = 0;
       
   754             gui_data->vts[vtid].images[id].area.y0 = 0;
       
   755         }
       
   756     } else {
       
   757         /* if it's not the background, ensure it is contained in it */
       
   758         switch(adjust_area_to_bg(vtid, &gui_data->vts[vtid].images[id].area)) {
       
   759         case AREA_CONTAINED_OK:
       
   760             break; /* OK */
       
   761         case AREA_NOT_CONTAINED:
       
   762             fprintf(stderr, "Warning: image id %d of vt %d outside background boundaries. Image ignored.\n", id, vtid);
       
   763             break;
       
   764         case AREA_DIMENSIONS_ADJUSTED:
       
   765             fprintf(stderr, "Warning: image id %d of vt %d outside background boundaries. Image cropped.\n", id, vtid);
       
   766             break;
       
   767         }
       
   768     }
       
   769 
       
   770     /* Support png only for now */
       
   771     gui_load_image_png(image_node->filename, &gui_data->vts[vtid].images[id]);
       
   772 }
       
   773 
       
   774 static void load_gui_displayarea(VtID vtid, DisplayID id, displayarea_node_t *displayarea_node)
       
   775 {
       
   776     if (adjust_area_to_bg(vtid, &displayarea_node->area) == AREA_CONTAINED_OK) {
       
   777         DisplayState * const ds = &gui_data->vts[vtid].ds_data[id].ds;
       
   778         ds->vtid = vtid;
       
   779         ds->dispid = id;
       
   780         ds->x0 = displayarea_node->area.x0;
       
   781         ds->y0 = displayarea_node->area.y0;
       
   782         ds->width = GET_GUI_AREA_WIDTH(&displayarea_node->area);
       
   783         ds->height = GET_GUI_AREA_HEIGHT(&displayarea_node->area);
       
   784         gui_data->host_callbacks.init_ds(ds);
       
   785         gui_update_ds_data(ds, 1);
       
   786         strcpy(gui_data->vts[vtid].ds_data[id].devid, displayarea_node->devid);
       
   787     } else
       
   788         fprintf(stderr, "Warning: displayarea id %d of vt %d outside background boundaries. Display ignored.", id, vtid);
       
   789 }
       
   790 
       
   791 static void load_gui_button(VtID vtid, int nbutton, const button_node_t *button_node)
       
   792 {
       
   793     const int area_id = gui_data->vts[vtid].clickable_map.n_areas++;
       
   794 
       
   795     /* fill button data */
       
   796     gui_data->vts[vtid].buttons[nbutton].pressed_img_id = button_node->pressed_img_id;
       
   797 
       
   798     if (button_node->action[0] == 0) {
       
   799         gui_data->vts[vtid].buttons[nbutton].actions = BUTTON_ACTION_NOACTION;
       
   800     } else if (strcmp(button_node->action, "sendkey") == 0) {
       
   801         gui_data->vts[vtid].buttons[nbutton].actions = BUTTON_ACTION_SENDKEY;
       
   802         gui_data->vts[vtid].buttons[nbutton].parameter = (void*)atol(button_node->parameter);
       
   803     } else {
       
   804         gui_data->vts[vtid].buttons[nbutton].actions = BUTTON_ACTION_NOACTION;
       
   805         fprintf(stderr, "Warning: unknown button action '%s'\n", button_node->action);
       
   806     }
       
   807 
       
   808     /* fill clickarea data */
       
   809     gui_data->vts[vtid].clickable_map.areas[area_id].area = button_node->area;
       
   810     gui_data->vts[vtid].clickable_map.areas[area_id].type = CA_BUTTON;
       
   811     gui_data->vts[vtid].clickable_map.areas[area_id].id = nbutton;
       
   812 }
       
   813 
       
   814 static void load_gui_pointerarea(VtID vtid, int nparea, const pointerarea_node_t *parea_node)
       
   815 {
       
   816     const int area_id = gui_data->vts[vtid].clickable_map.n_areas++;
       
   817 
       
   818     /* fill pointerarea data */
       
   819     strcpy(gui_data->vts[vtid].pointerareas[nparea].devid, parea_node->devid);
       
   820     gui_data->vts[vtid].pointerareas[nparea].absolute = parea_node->absolute;
       
   821     gui_data->vts[vtid].pointerareas[nparea].grab_on_click = parea_node->grab_on_click;
       
   822     gui_data->vts[vtid].pointerareas[nparea].show_cursor_while_grabbing = parea_node->show_cursor_while_grabbing;
       
   823 
       
   824     /* fill clickarea data */
       
   825     gui_data->vts[vtid].clickable_map.areas[area_id].area = parea_node->area;
       
   826     gui_data->vts[vtid].clickable_map.areas[area_id].type = CA_POINTERAREA;
       
   827     gui_data->vts[vtid].clickable_map.areas[area_id].id = nparea;
       
   828 }
       
   829 
       
   830 #define FLATTEN(type,first_node,function)   \
       
   831     {                                       \
       
   832         type *node = first_node;            \
       
   833         type *next;                         \
       
   834         unsigned int i = 0;                 \
       
   835         while(node != NULL) {               \
       
   836             function(i, node);              \
       
   837             next = node->next;              \
       
   838             qemu_free(node);                \
       
   839             node = next;                    \
       
   840             i++;                            \
       
   841         }                                   \
       
   842     }
       
   843 
       
   844 #define VT_FLATTEN(type,vtid,first_node,function)   \
       
   845     {                                               \
       
   846         type *node = first_node;                    \
       
   847         type *next;                                 \
       
   848         unsigned int i = 0;                         \
       
   849         while(node != NULL) {                       \
       
   850             function(vtid, i, node);                \
       
   851             next = node->next;                      \
       
   852             qemu_free(node);                        \
       
   853             node = next;                            \
       
   854             i++;                                    \
       
   855         }                                           \
       
   856     }
       
   857 
       
   858 #define ALLOC_ARRAY(type,n) (type*)qemu_mallocz((n)*sizeof(type))
       
   859 
       
   860 
       
   861 static void load_gui_vt(int nvt, const vt_node_t *vt_node)
       
   862 {
       
   863     const VtID vt = insert_new_vt(SKINNED_VT_PRIORITY_ORDER); /* nvt + gui_data->n_vts;*/
       
   864     int n_clickareas = 0;
       
   865 
       
   866     gui_data->vts[vt].has_skin = 1;
       
   867 
       
   868     /* allocate memory first */
       
   869     gui_data->vts[vt].n_images = vt_node->n_images;
       
   870     if (vt_node->n_images > 0)
       
   871         gui_data->vts[vt].images = ALLOC_ARRAY(gui_image_t, vt_node->n_images);
       
   872 
       
   873     n_clickareas = vt_node->n_buttons + vt_node->n_pointerareas;
       
   874     if (n_clickareas > 0)
       
   875         gui_data->vts[vt].clickable_map.areas = ALLOC_ARRAY(clickable_area_t, n_clickareas);
       
   876     gui_data->vts[vt].clickable_map.n_areas = 0; /* will be incremented while
       
   877                                                     loading buttons and pointerareas */
       
   878 
       
   879     gui_data->vts[vt].n_buttons = vt_node->n_buttons;
       
   880     if (vt_node->n_buttons > 0)
       
   881         gui_data->vts[vt].buttons = ALLOC_ARRAY(button_t, vt_node->n_buttons);
       
   882 
       
   883     gui_data->vts[vt].n_pointerareas = vt_node->n_pointerareas;
       
   884     if (vt_node->n_pointerareas > 0)
       
   885         gui_data->vts[vt].pointerareas = ALLOC_ARRAY(pointer_area_t, vt_node->n_pointerareas);
       
   886 
       
   887     gui_data->vts[vt].n_ds = vt_node->n_displayareas;
       
   888     if (vt_node->n_displayareas > 0)
       
   889         gui_data->vts[vt].ds_data = ALLOC_ARRAY(ds_data_t, vt_node->n_displayareas);
       
   890 
       
   891     /* flatten subtrees */
       
   892     VT_FLATTEN(image_node_t,       vt, vt_node->first_image_node,       load_gui_image);
       
   893     VT_FLATTEN(button_node_t,      vt, vt_node->first_button_node,      load_gui_button);
       
   894     VT_FLATTEN(pointerarea_node_t, vt, vt_node->first_pointerarea_node, load_gui_pointerarea);
       
   895     VT_FLATTEN(displayarea_node_t, vt, vt_node->first_displayarea_node, load_gui_displayarea);
       
   896 }
       
   897 
       
   898 static parse_result_t load_gui_xml(const char* xml_file)
       
   899 {
       
   900     gui_xml_tree_t gui_xml_tree;
       
   901     parse_result_t ret;
       
   902 
       
   903     /* 1: parse the file */
       
   904     ret = parse_gui_xml(xml_file, &gui_xml_tree);
       
   905     if (ret != PARSE_OK)
       
   906         return ret;
       
   907 
       
   908     /* 2: allocate memory */
       
   909     if (gui_xml_tree.n_vts == 0) {
       
   910         fprintf(stderr, "GUI Error: at least one VT shall be defined\n");
       
   911         return UNEXPECTED_EOF;
       
   912     }
       
   913 
       
   914     FLATTEN(vt_node_t, gui_xml_tree.first_vt_node, load_gui_vt);
       
   915 
       
   916     return ret;
       
   917 }
       
   918 
       
   919 #undef ALLOC_ARRAY
       
   920 #undef FLATTEN
       
   921 #undef VT_FLATTEN
       
   922 
       
   923 static void index_map(clickable_map_t *map)
       
   924 {
       
   925     /* TODO: no geometrical index implemented yet */
       
   926 }
       
   927 
       
   928 static void initialize_display_areas(VtID vtid)
       
   929 {
       
   930     int nds;
       
   931     for(nds = 0; nds < gui_data->vts[vtid].n_ds; nds++) {
       
   932         gui_data->host_callbacks.init_ds(&gui_data->vts[vtid].ds_data[nds].ds);
       
   933         gui_update_ds_data(&gui_data->vts[vtid].ds_data[nds].ds, gui_data->vts[vtid].has_skin);
       
   934     }
       
   935 }
       
   936 
       
   937 static void destroy_images(VtID vtid)
       
   938 {
       
   939     int i;
       
   940     for (i=0; i<gui_data->vts[vtid].n_images; i++)
       
   941         qemu_free(gui_data->vts[vtid].images[i].image);
       
   942 
       
   943     qemu_free(gui_data->vts[vtid].images);
       
   944 }
       
   945 
       
   946 static void destroy_clickable_map(clickable_map_t *map)
       
   947 {
       
   948     qemu_free(map->areas);
       
   949 }
       
   950 
       
   951 static inline int area_contains(const gui_area_t *area, int x, int y)
       
   952 {
       
   953 #define IN_RANGE(min,value,max) ((min)<=(value) && (value)<=(max))
       
   954     return IN_RANGE(area->x0, x, area->x1) && IN_RANGE(area->y0, y, area->y1);
       
   955 #undef IN_RANGE
       
   956 }
       
   957 
       
   958 /* TODO: Optimize with a geometrical index! */
       
   959 static clickable_area_t *find_clickarea(const vt_t *vt, int x, int y, AreaID *id_found)
       
   960 {
       
   961     AreaID id = 0;
       
   962     int found = 0;
       
   963     clickable_area_t * carea;
       
   964 
       
   965     while (id < vt->clickable_map.n_areas && !found) {
       
   966         carea = &vt->clickable_map.areas[id++];
       
   967         found = area_contains(&carea->area, x, y);
       
   968     }
       
   969 
       
   970     if (found) {
       
   971         *id_found = id-1;
       
   972         return carea;
       
   973     } else
       
   974         return NULL;
       
   975 }
       
   976 
       
   977 static inline int grabbing_mouse(void)
       
   978 {
       
   979     if (vt_enabled())
       
   980         return gui_data->current_vt->clickable_map.currently_grabbing != NULL;
       
   981     else
       
   982         return 0;
       
   983 }
       
   984 
       
   985 static inline int gui_grabbing(void)
       
   986 {
       
   987     return grabbing_mouse() /*TODO when implementing VNC: || grabbing_kbd()*/;
       
   988 }
       
   989 
       
   990 static pointer_area_t *current_parea(void)
       
   991 {
       
   992     if (vt_enabled())
       
   993         if (gui_data->current_vt->clickable_map.currently_grabbing != NULL)
       
   994             return &gui_data->current_vt->pointerareas[
       
   995                 gui_data->current_vt->clickable_map.currently_grabbing->id
       
   996             ];
       
   997         else
       
   998             return NULL;
       
   999     else
       
  1000         return NULL;
       
  1001 }
       
  1002 
       
  1003 /************************* Input Host Functions ****************************/
       
  1004 
       
  1005 /* Wrappers and functions to common states */
       
  1006 
       
  1007 static void gui_update_caption(void)
       
  1008 {
       
  1009     if(gui_data->host_callbacks.set_caption != NULL) {
       
  1010         char buf[1024];
       
  1011         const char *status = "";
       
  1012         int grabbing;
       
  1013 
       
  1014         if (gui_data->loaded)
       
  1015             grabbing = (gui_data->current_vt->clickable_map.currently_grabbing != NULL);
       
  1016         else
       
  1017             grabbing = gui_data->unloaded_state_data.gui_grab;
       
  1018 
       
  1019 
       
  1020         if (!vm_running)
       
  1021             status = " [Stopped]";
       
  1022         else if (grabbing) {
       
  1023             if (!alt_grab)
       
  1024                 status = " - Press Ctrl-Alt to exit grab";
       
  1025             else
       
  1026                 status = " - Press Ctrl-Alt-Shift to exit grab";
       
  1027         }
       
  1028 
       
  1029         if (qemu_name)
       
  1030             snprintf(buf, sizeof(buf), "QEMU (%s)%s", qemu_name, status);
       
  1031         else
       
  1032             snprintf(buf, sizeof(buf), "QEMU%s", status);
       
  1033 
       
  1034         gui_data->host_callbacks.set_caption(buf, "QEMU");
       
  1035     }
       
  1036 }
       
  1037 
       
  1038 int gui_allows_fullscreen(void)
       
  1039 {
       
  1040     return (gui_data->host_callbacks.set_screen_size != NULL);
       
  1041 }
       
  1042 
       
  1043 void gui_notify_toggle_fullscreen(void)
       
  1044 {
       
  1045     gui_data->input_table->gui_notify_toggle_fullscreen();
       
  1046 }
       
  1047 
       
  1048 void gui_notify_mouse_motion(int dx, int dy, int dz, int x, int y, int state)
       
  1049 {
       
  1050     gui_data->input_table->gui_notify_mouse_motion(dx, dy, dz, x, y, state);
       
  1051 }
       
  1052 
       
  1053 void gui_notify_mouse_button(int dz, int x, int y, int state)
       
  1054 {
       
  1055     gui_data->input_table->gui_notify_mouse_button(dz, x, y, state);
       
  1056 }
       
  1057 
       
  1058 void gui_notify_mouse_warp(int x, int y, int on)
       
  1059 {
       
  1060     gui_data->input_table->gui_notify_mouse_warp(x, y, on);
       
  1061 }
       
  1062 
       
  1063 void gui_notify_term_key(int keysym)
       
  1064 {
       
  1065     if (vt_enabled()) {
       
  1066         if (gui_data->current_vt->key_callback != NULL)
       
  1067             gui_data->current_vt->key_callback(
       
  1068                 gui_data->current_vt->key_opaque,
       
  1069                 keysym);
       
  1070     }
       
  1071 }
       
  1072 
       
  1073 void gui_notify_dev_key(int keysym)
       
  1074 {
       
  1075     if (vt_enabled()) {
       
  1076         if (gui_data->dev_key_callback != NULL)
       
  1077             gui_data->dev_key_callback(
       
  1078                 gui_data->dev_key_opaque,
       
  1079                 keysym);
       
  1080     }
       
  1081 }
       
  1082 
       
  1083 static void gui_notify_console_select_by_vtid(VtID console)
       
  1084 {
       
  1085     if (console < gui_data->n_vts) {
       
  1086         const int vt_width = get_vt_width(&gui_data->vts[console]);
       
  1087         const int vt_height = get_vt_height(&gui_data->vts[console]);
       
  1088         int disp;
       
  1089         gui_data->current_vt = &gui_data->vts[console];
       
  1090         if (vt_width != gui_data->screen_data.width ||
       
  1091             vt_height != gui_data->screen_data.height) {
       
  1092 
       
  1093             gui_data->host_callbacks.set_screen_size(vt_width, vt_height, gui_data->gui_fullscreen);
       
  1094             gui_data->host_callbacks.get_screen_data(&gui_data->screen_data);
       
  1095         }
       
  1096 
       
  1097         if (gui_data->vts[console].has_skin)
       
  1098             gui_update_ds_data(&gui_data->vts[console].gui_ds, 1);
       
  1099         gui_data->current_vt->full_update = 1;
       
  1100 
       
  1101         for (disp=0; disp < gui_data->current_vt->n_ds; disp++) {
       
  1102             gui_update_ds_data(&gui_data->current_vt->ds_data[disp].ds, gui_data->vts[console].has_skin);
       
  1103             if (gui_data->current_vt->ds_data[disp].invalidate != NULL)
       
  1104                 gui_data->current_vt->ds_data[disp].invalidate(
       
  1105                     gui_data->current_vt->ds_data[disp].opaque
       
  1106                 );
       
  1107         }
       
  1108 
       
  1109         /* determine kbd terminal mode */
       
  1110         if (gui_data->host_callbacks.set_kbd_terminal_mode != NULL)
       
  1111             gui_data->host_callbacks.set_kbd_terminal_mode(gui_data->current_vt->key_callback != NULL);
       
  1112     } else
       
  1113         gui_data->current_vt = NULL;
       
  1114 
       
  1115 /*    if (!gui_is_graphic_console()) { */
       
  1116     if (gui_data->current_vt != NULL && accepts_kbd(gui_data->current_vt)) {
       
  1117         /* display grab if going to a text console */
       
  1118         if (gui_grabbing())
       
  1119             gui_loaded_grab_end();
       
  1120     }
       
  1121 
       
  1122 }
       
  1123 
       
  1124 static VtID gui_get_console_order_vtid(int console_order)
       
  1125 {
       
  1126     return gui_data->ordered_vts[console_order];
       
  1127 }
       
  1128 
       
  1129 void gui_notify_console_select(int console_order)
       
  1130 {
       
  1131     if (console_order < gui_data->n_vts)
       
  1132         gui_notify_console_select_by_vtid(gui_get_console_order_vtid(console_order));
       
  1133 }
       
  1134 
       
  1135 void gui_notify_activate_display(DisplayState *ds)
       
  1136 {
       
  1137     gui_notify_console_select_by_vtid(ds->vtid);
       
  1138 }
       
  1139 
       
  1140 void gui_notify_toggle_grabmode(void)
       
  1141 {
       
  1142     gui_data->input_table->gui_notify_toggle_grabmode();
       
  1143 }
       
  1144 
       
  1145 void gui_notify_new_guest_cursor(void)
       
  1146 {
       
  1147     gui_data->input_table->gui_notify_new_guest_cursor();
       
  1148 }
       
  1149 
       
  1150 void gui_notify_input_focus_lost(void)
       
  1151 {
       
  1152     gui_data->input_table->gui_notify_input_focus_lost();
       
  1153 }
       
  1154 
       
  1155 void gui_notify_update_tick(int64_t ticks)
       
  1156 {
       
  1157     if (vt_enabled()) {
       
  1158         int disp;
       
  1159 
       
  1160         if (gui_data->current_vt->full_update) {
       
  1161             /* update the background */
       
  1162             if (gui_data->current_vt->has_skin)
       
  1163                 gui_update_guest_display(gui_data->current_vt);
       
  1164 
       
  1165             for (disp=0; disp < gui_data->current_vt->n_ds; disp++)
       
  1166                 invalidate_ds(&gui_data->current_vt->ds_data[disp]);
       
  1167         }
       
  1168 
       
  1169         gui_data->updating = 1;
       
  1170 
       
  1171         for (disp=0; disp < gui_data->current_vt->n_ds; disp++)
       
  1172             update_ds(&gui_data->current_vt->ds_data[disp]);
       
  1173 
       
  1174         gui_data->updating = 0;
       
  1175     }
       
  1176 
       
  1177     gui_data->host_callbacks.process_events();
       
  1178 
       
  1179     gui_update_timer(ticks);
       
  1180 }
       
  1181 
       
  1182 void gui_notify_app_focus(int gain)
       
  1183 {
       
  1184     gui_data->input_table->gui_notify_app_focus(gain);
       
  1185 }
       
  1186 
       
  1187 void gui_notify_idle(int idle)
       
  1188 {
       
  1189     gui_data->idle = idle;
       
  1190 }
       
  1191 
       
  1192 void gui_notify_repaint_screen(void)
       
  1193 {
       
  1194     if (vt_enabled()) {
       
  1195         int disp;
       
  1196 
       
  1197         /* update the background */
       
  1198         if (gui_data->current_vt->has_skin) {
       
  1199             dpy_update(&gui_data->current_vt->gui_ds,
       
  1200                        0,
       
  1201                        0,
       
  1202                        gui_data->current_vt->gui_ds.width,
       
  1203                        gui_data->current_vt->gui_ds.height
       
  1204                       );
       
  1205         }
       
  1206 
       
  1207         for (disp=0; disp < gui_data->current_vt->n_ds; disp++) {
       
  1208             dpy_update(&gui_data->current_vt->ds_data[disp].ds,
       
  1209                        0,
       
  1210                        0,
       
  1211                        gui_data->current_vt->ds_data[disp].ds.width,
       
  1212                        gui_data->current_vt->ds_data[disp].ds.height
       
  1213                       );
       
  1214         }
       
  1215     }
       
  1216 }
       
  1217 
       
  1218 void gui_notify_screen_dump(const char *filename)
       
  1219 {
       
  1220     if (vt_enabled()) {
       
  1221         if (gui_data->current_vt->n_ds > 0 &&
       
  1222             gui_data->current_vt->ds_data[0].screen_dump != NULL) {
       
  1223             gui_data->current_vt->ds_data[0].screen_dump(
       
  1224                 gui_data->current_vt->ds_data[0].opaque,
       
  1225                 filename);
       
  1226         }
       
  1227     }
       
  1228 }
       
  1229 
       
  1230 int gui_is_display_active(DisplayState *ds)
       
  1231 {
       
  1232     return (gui_data->current_vt - gui_data->vts) == ds->vtid;
       
  1233 }
       
  1234 
       
  1235 void gui_refresh_caption(void)
       
  1236 {
       
  1237     if (gui_data->last_vm_running != vm_running) {
       
  1238         gui_data->last_vm_running = vm_running;
       
  1239         gui_update_caption();
       
  1240     }
       
  1241 }
       
  1242 
       
  1243 static void gui_update_timer(int64_t ticks)
       
  1244 {
       
  1245     qemu_mod_timer(gui_data->gui_timer,
       
  1246         (gui_data->gui_timer_interval ?
       
  1247 	    gui_data->gui_timer_interval :
       
  1248 	    GUI_REFRESH_INTERVAL)
       
  1249 	+ ticks);
       
  1250 }
       
  1251 
       
  1252 static inline int col_to_bytes(int bpp, int col)
       
  1253 {
       
  1254     switch(bpp) {
       
  1255     case 32:
       
  1256         return col * 4;
       
  1257     case 24:
       
  1258         return col * 3;
       
  1259     case 16:
       
  1260     case 15:
       
  1261         return col * 2;
       
  1262     case 8:
       
  1263         return col;
       
  1264     case 4:
       
  1265         return col >> 1;
       
  1266     case 2:
       
  1267         return col >> 2;
       
  1268     case 1:
       
  1269         return col >> 3;
       
  1270     default:
       
  1271         return 0;
       
  1272     }
       
  1273 }
       
  1274 
       
  1275 static void gui_update_ds_data(DisplayState *ds, int in_skinned_vt)
       
  1276 {
       
  1277 #if 0
       
  1278     DFG: TODO: see why this comes wrong
       
  1279     ds->linesize = gui_data->screen_data.linesize;
       
  1280 #endif
       
  1281     ds->depth = gui_data->screen_data.depth;
       
  1282     ds->bgr = gui_data->screen_data.bgr;
       
  1283     if (in_skinned_vt) {
       
  1284         ds->linesize = col_to_bytes(ds->depth, gui_data->screen_data.width);
       
  1285         /* calc offset */
       
  1286         ds->data = gui_data->screen_data.data + ds->y0 * ds->linesize + col_to_bytes(ds->depth, ds->x0);
       
  1287     } else {
       
  1288         ds->linesize = gui_data->screen_data.linesize;
       
  1289         ds->data = gui_data->screen_data.data;
       
  1290     }
       
  1291 
       
  1292 }
       
  1293 
       
  1294 /* ************ GUI UNLOADED VERSION ********************/
       
  1295 
       
  1296 static void gui_unloaded_hide_cursor(void)
       
  1297 {
       
  1298     if (!cursor_hide)
       
  1299         return;
       
  1300 
       
  1301     if (kbd_mouse_is_absolute()) {
       
  1302         gui_data->host_callbacks.turn_cursor_on(GUI_CURSOR_HIDDEN);
       
  1303     } else {
       
  1304         gui_data->host_callbacks.turn_cursor_off();
       
  1305     }
       
  1306 }
       
  1307 
       
  1308 static void gui_unloaded_show_cursor(void)
       
  1309 {
       
  1310     gui_cursor_type_t cursor_type;
       
  1311 
       
  1312     if (!cursor_hide)
       
  1313         return;
       
  1314 
       
  1315     if (!kbd_mouse_is_absolute()) {
       
  1316         if (gui_data->guest_cursor &&
       
  1317                 (gui_data->unloaded_state_data.gui_grab || 
       
  1318                  kbd_mouse_is_absolute() || 
       
  1319                  gui_data->unloaded_state_data.absolute_enabled))
       
  1320             cursor_type = GUI_CURSOR_GUEST_SPRITE;
       
  1321         else
       
  1322             cursor_type = GUI_CURSOR_NORMAL;
       
  1323         
       
  1324         gui_data->host_callbacks.turn_cursor_on(cursor_type);
       
  1325     }
       
  1326 }
       
  1327 
       
  1328 static void gui_unloaded_grab_start(void)
       
  1329 {
       
  1330     if (gui_data->guest_cursor) {
       
  1331         gui_data->host_callbacks.turn_cursor_on(GUI_CURSOR_GUEST_SPRITE);
       
  1332         gui_data->host_callbacks.mouse_warp(gui_data->guest_x, 
       
  1333                                             gui_data->guest_y);
       
  1334     } else
       
  1335         gui_unloaded_hide_cursor();
       
  1336 
       
  1337     gui_data->host_callbacks.grab_input_on();
       
  1338     gui_data->unloaded_state_data.gui_grab = 1;
       
  1339     gui_update_caption();
       
  1340 }
       
  1341 
       
  1342 static void gui_unloaded_grab_end(void)
       
  1343 {
       
  1344     gui_data->host_callbacks.grab_input_off();
       
  1345     gui_data->unloaded_state_data.gui_grab = 0;
       
  1346     gui_unloaded_show_cursor();
       
  1347     gui_update_caption();
       
  1348 }
       
  1349 
       
  1350 static void gui_unloaded_send_mouse_event(int dx, int dy, int dz, int x, int y, int state)
       
  1351 {
       
  1352     if (kbd_mouse_is_absolute()) {
       
  1353         if (!gui_data->unloaded_state_data.absolute_enabled) {
       
  1354             gui_unloaded_hide_cursor();
       
  1355             if (gui_data->unloaded_state_data.gui_grab) {
       
  1356 	            gui_unloaded_grab_end();
       
  1357             }
       
  1358             gui_data->unloaded_state_data.absolute_enabled = 1;
       
  1359         }
       
  1360 
       
  1361         dx = x * 0x7FFF / (gui_data->screen_data.width - 1);
       
  1362         dy = y * 0x7FFF / (gui_data->screen_data.height - 1);
       
  1363     } else if (gui_data->unloaded_state_data.absolute_enabled) {
       
  1364         gui_unloaded_show_cursor();
       
  1365         gui_data->unloaded_state_data.absolute_enabled = 0;
       
  1366     } else if (gui_data->guest_cursor) {
       
  1367         /* calc relative coords 
       
  1368             dx = x - guest_x
       
  1369             dy = y - guest_y
       
  1370         */
       
  1371         x -= gui_data->guest_x;
       
  1372         y -= gui_data->guest_y;
       
  1373         gui_data->guest_x += x;
       
  1374         gui_data->guest_y += y;
       
  1375         dx = x;
       
  1376         dy = y;
       
  1377     }
       
  1378 
       
  1379     kbd_mouse_event(dx, dy, dz, state);
       
  1380 }
       
  1381 
       
  1382 static void gui_unloaded_notify_toggle_fullscreen(void)
       
  1383 {
       
  1384     gui_data->gui_fullscreen = !gui_data->gui_fullscreen;
       
  1385 
       
  1386     if (gui_data->gui_fullscreen) {
       
  1387         gui_data->unloaded_state_data.gui_saved_grab = 
       
  1388             gui_data->unloaded_state_data.gui_grab;
       
  1389         gui_unloaded_grab_start();
       
  1390     } else {
       
  1391         if (!gui_data->unloaded_state_data.gui_saved_grab)
       
  1392             gui_unloaded_grab_end();
       
  1393     }
       
  1394 
       
  1395     gui_data->host_callbacks.set_screen_size(
       
  1396         gui_data->screen_data.width,
       
  1397         gui_data->screen_data.height,
       
  1398         gui_data->gui_fullscreen);
       
  1399 
       
  1400     gui_data->host_callbacks.get_screen_data(&gui_data->screen_data);
       
  1401 
       
  1402     gui_notify_console_select_by_vtid(current_vt_id());
       
  1403 }
       
  1404 
       
  1405 static void gui_unloaded_notify_mouse_motion(int dx, int dy, int dz, int x, int y, int state)
       
  1406 {
       
  1407     if (gui_data->unloaded_state_data.gui_grab || 
       
  1408         kbd_mouse_is_absolute() ||
       
  1409         gui_data->unloaded_state_data.absolute_enabled) {
       
  1410         gui_unloaded_send_mouse_event(dx, dy, dz, x, y, state);
       
  1411     }
       
  1412 }
       
  1413 
       
  1414 static void gui_unloaded_notify_mouse_button(int dz, int x, int y, int state)
       
  1415 {
       
  1416     if (gui_data->unloaded_state_data.gui_grab || kbd_mouse_is_absolute()) {
       
  1417         gui_unloaded_send_mouse_event(0, 0, dz, x, y, state);
       
  1418     } else {
       
  1419         if (state == MOUSE_EVENT_LBUTTON) {
       
  1420             /* start grabbing all events */
       
  1421             gui_unloaded_grab_start();
       
  1422         }
       
  1423     }
       
  1424 }
       
  1425 
       
  1426 static void gui_unloaded_notify_mouse_warp(int x, int y, int on)
       
  1427 {
       
  1428     if (on) {
       
  1429         if (!gui_data->guest_cursor)
       
  1430             gui_unloaded_show_cursor();
       
  1431         if (gui_data->unloaded_state_data.gui_grab || 
       
  1432             kbd_mouse_is_absolute() || 
       
  1433             gui_data->unloaded_state_data.absolute_enabled) {
       
  1434             gui_data->host_callbacks.turn_cursor_on(GUI_CURSOR_GUEST_SPRITE);
       
  1435             gui_data->host_callbacks.mouse_warp(gui_data->guest_x, 
       
  1436                                                 gui_data->guest_y);
       
  1437         }
       
  1438     } else if (gui_data->unloaded_state_data.gui_grab)
       
  1439         gui_unloaded_hide_cursor();
       
  1440     gui_data->guest_cursor = on;
       
  1441     gui_data->guest_x = x;
       
  1442     gui_data->guest_y = y;
       
  1443 }
       
  1444 
       
  1445 static void gui_unloaded_notify_toggle_grabmode(void)
       
  1446 {
       
  1447     if (!gui_data->unloaded_state_data.gui_grab) {
       
  1448         int app_active = 1;
       
  1449 
       
  1450         /* if the application is not active,
       
  1451            do not try to enter grab state. It
       
  1452            prevents
       
  1453            'SDL_WM_GrabInput(SDL_GRAB_ON)'
       
  1454            from blocking all the application
       
  1455            (SDL bug). */
       
  1456         if (gui_data->host_callbacks.is_app_active != NULL)
       
  1457             app_active = gui_data->host_callbacks.is_app_active();
       
  1458 
       
  1459         if (app_active)
       
  1460             gui_unloaded_grab_start();
       
  1461     } else {
       
  1462         gui_unloaded_grab_end();
       
  1463     }
       
  1464 }
       
  1465 
       
  1466 static void gui_unloaded_notify_new_guest_cursor(void)
       
  1467 {
       
  1468     /* DFG: DANGER, this call also invokes show_cursor() */
       
  1469     if (gui_data->guest_cursor &&
       
  1470             (gui_data->unloaded_state_data.gui_grab || 
       
  1471              kbd_mouse_is_absolute() || 
       
  1472              gui_data->unloaded_state_data.absolute_enabled))
       
  1473         gui_data->host_callbacks.turn_cursor_on(GUI_CURSOR_GUEST_SPRITE);
       
  1474 }
       
  1475 
       
  1476 static void gui_unloaded_notify_input_focus_lost(void)
       
  1477 {
       
  1478     if (gui_data->unloaded_state_data.gui_grab && 
       
  1479         !gui_data->unloaded_state_data.gui_fullscreen_initial_grab)
       
  1480         gui_unloaded_grab_end();
       
  1481 }
       
  1482 
       
  1483 static void gui_unloaded_notify_app_focus(int gain)
       
  1484 {
       
  1485     if (gain) {
       
  1486         /* Back to default interval */
       
  1487         gui_data->gui_timer_interval = 0;
       
  1488         gui_data->idle = 0;
       
  1489     } else {
       
  1490         /* Sleeping interval */
       
  1491         gui_data->gui_timer_interval = 500;
       
  1492         gui_data->idle = 1;
       
  1493     }
       
  1494 }
       
  1495 
       
  1496 /******************* GUI LOADED VERSION *********************/
       
  1497 
       
  1498 static void gui_loaded_hide_cursor(void)
       
  1499 {
       
  1500     if (!cursor_hide)
       
  1501         return;
       
  1502 
       
  1503     gui_data->host_callbacks.turn_cursor_off();
       
  1504 }
       
  1505 
       
  1506 static void gui_loaded_show_cursor(void)
       
  1507 {
       
  1508     gui_cursor_type_t cursor_type;
       
  1509 
       
  1510     if (!cursor_hide)
       
  1511         return;
       
  1512 
       
  1513     if (gui_grabbing()) {
       
  1514         if (gui_data->guest_cursor && current_parea() != NULL &&
       
  1515             current_parea()->show_cursor_while_grabbing) {
       
  1516             cursor_type = GUI_CURSOR_GUEST_SPRITE;
       
  1517         }else
       
  1518             cursor_type = GUI_CURSOR_NORMAL;
       
  1519     } else
       
  1520         cursor_type = GUI_CURSOR_NORMAL;
       
  1521 
       
  1522     gui_data->host_callbacks.turn_cursor_on(cursor_type);
       
  1523 }
       
  1524 
       
  1525 static void gui_loaded_grab_start(void)
       
  1526 {
       
  1527     if (gui_data->guest_cursor) {
       
  1528         gui_data->host_callbacks.turn_cursor_on(GUI_CURSOR_GUEST_SPRITE);
       
  1529         gui_data->host_callbacks.mouse_warp(gui_data->guest_x, 
       
  1530                                             gui_data->guest_y);
       
  1531     } else
       
  1532         gui_loaded_hide_cursor();
       
  1533 
       
  1534     gui_data->host_callbacks.grab_input_on();
       
  1535     gui_update_caption();
       
  1536 }
       
  1537 
       
  1538 static void gui_loaded_grab_end(void)
       
  1539 {
       
  1540     gui_data->host_callbacks.grab_input_off();
       
  1541     gui_data->current_vt->clickable_map.currently_grabbing = NULL;
       
  1542     gui_loaded_show_cursor();
       
  1543     gui_update_caption();
       
  1544 }
       
  1545 
       
  1546 static void gui_loaded_send_mouse_event(clickable_area_t *carea, int dx, int dy, int dz, int x, int y, int state)
       
  1547 {
       
  1548     pointer_area_t * const parea = &gui_data->current_vt->pointerareas[carea->id];
       
  1549 
       
  1550     if (parea->absolute) {
       
  1551         dx = x * 0x7FFF / (GET_GUI_AREA_WIDTH(&carea->area)- 1);
       
  1552         dy = y * 0x7FFF / (GET_GUI_AREA_HEIGHT(&carea->area) - 1);
       
  1553     } else if (gui_data->guest_cursor) {
       
  1554         /* calc relative coords 
       
  1555             dx = x - guest_x
       
  1556             dy = y - guest_y
       
  1557         */
       
  1558         x -= gui_data->guest_x;
       
  1559         y -= gui_data->guest_y;
       
  1560         gui_data->guest_x += x;
       
  1561         gui_data->guest_y += y;
       
  1562         dx = x;
       
  1563         dy = y;
       
  1564     }
       
  1565 
       
  1566     parea->callback(parea->opaque, dx, dy, dz, state);
       
  1567 }
       
  1568 
       
  1569 static void gui_loaded_notify_toggle_fullscreen(void)
       
  1570 {
       
  1571     gui_data->gui_fullscreen = !gui_data->gui_fullscreen;
       
  1572 
       
  1573     gui_data->host_callbacks.set_screen_size(
       
  1574         gui_data->screen_data.width,
       
  1575         gui_data->screen_data.height,
       
  1576         gui_data->gui_fullscreen);
       
  1577 
       
  1578     gui_data->host_callbacks.get_screen_data(&gui_data->screen_data);
       
  1579 
       
  1580     gui_notify_console_select_by_vtid(current_vt_id());
       
  1581 
       
  1582 }
       
  1583 
       
  1584 static void gui_loaded_notify_mouse_motion(int dx, int dy, int dz, int x, int y, int state)
       
  1585 {
       
  1586     if (vt_enabled()) {
       
  1587         if (gui_grabbing() /*|| kbd_mouse_is_absolute() ||
       
  1588             absolute_enabled*/) {
       
  1589             gui_loaded_send_mouse_event(gui_data->current_vt->clickable_map.currently_grabbing, dx, dy, dz, x, y, state);
       
  1590         }
       
  1591     }
       
  1592 }
       
  1593 
       
  1594 static void gui_loaded_notify_mouse_button(int dz, int x, int y, int state)
       
  1595 {
       
  1596     if (vt_enabled()) {
       
  1597         clickable_area_t *forward_area = NULL;
       
  1598 
       
  1599         /* If we're not grabbing, check if we should start due to click on a pointerarea */
       
  1600 
       
  1601         if (grabbing_mouse())
       
  1602             forward_area = gui_data->current_vt->clickable_map.currently_grabbing;
       
  1603         else {
       
  1604             AreaID id;
       
  1605             clickable_area_t *carea = find_clickarea(gui_data->current_vt, x, y, &id);
       
  1606 
       
  1607             if (carea != NULL) {
       
  1608                 if (carea->type == CA_BUTTON) {
       
  1609                     if (state == MOUSE_EVENT_LBUTTON) {
       
  1610                         if (gui_data->current_vt->buttons[carea->id].pressed_img_id > 0)
       
  1611                             gui_show_image(current_vt_id(),
       
  1612                                            gui_data->current_vt->buttons[carea->id].pressed_img_id);
       
  1613 
       
  1614                         button_actions[gui_data->current_vt->buttons[carea->id].actions].down(gui_data->current_vt->buttons[carea->id].parameter);
       
  1615                     } else {
       
  1616                         gui_hide_image(current_vt_id(),
       
  1617                                        gui_data->current_vt->buttons[carea->id].pressed_img_id);
       
  1618                         button_actions[gui_data->current_vt->buttons[carea->id].actions].up(gui_data->current_vt->buttons[carea->id].parameter);
       
  1619                     }
       
  1620                 } else { /* pointerarea*/
       
  1621                     /* get the associated pointerarea */
       
  1622                     pointer_area_t * const parea = &gui_data->current_vt->pointerareas[carea->id];
       
  1623                     if (parea->grab_on_click) {
       
  1624                         if (state == MOUSE_EVENT_LBUTTON) {
       
  1625                             gui_data->current_vt->clickable_map.currently_grabbing = carea;
       
  1626                             gui_loaded_grab_start();
       
  1627                         } /* else: ignore */
       
  1628                     } else
       
  1629                         forward_area = carea;
       
  1630                 }
       
  1631             }
       
  1632         }
       
  1633 
       
  1634         if (forward_area != NULL)
       
  1635             gui_loaded_send_mouse_event(forward_area, 0, 0, dz, x, y, state);
       
  1636     }
       
  1637 }
       
  1638 
       
  1639 static void gui_loaded_notify_mouse_warp(int x, int y, int on)
       
  1640 {
       
  1641     if (on) {
       
  1642         if (!gui_data->guest_cursor)
       
  1643             gui_loaded_show_cursor();
       
  1644         if (gui_grabbing() /*|| kbd_mouse_is_absolute() || absolute_enabled*/) {
       
  1645             gui_data->host_callbacks.turn_cursor_on(GUI_CURSOR_GUEST_SPRITE);
       
  1646             gui_data->host_callbacks.mouse_warp(gui_data->guest_x,
       
  1647                                                 gui_data->guest_y);
       
  1648         }
       
  1649     } else if (gui_grabbing())
       
  1650         gui_loaded_hide_cursor();
       
  1651     gui_data->guest_cursor = on;
       
  1652     gui_data->guest_x = x;
       
  1653     gui_data->guest_y = y;
       
  1654 }
       
  1655 
       
  1656 static void gui_loaded_notify_toggle_grabmode(void)
       
  1657 {
       
  1658     if (vt_enabled()) {
       
  1659         if (!gui_grabbing()) {
       
  1660 #if 0
       
  1661             /* TODO DFG : distinguish between mouse and kbd grabbing. Do this when
       
  1662                implementing VNC support. */
       
  1663             int app_active = 1;
       
  1664 
       
  1665             /* if the application is not active,
       
  1666                do not try to enter grab state. It
       
  1667                prevents
       
  1668                'SDL_WM_GrabInput(SDL_GRAB_ON)'
       
  1669                from blocking all the application
       
  1670                (SDL bug). */
       
  1671             if (gui_data->host_callbacks.is_app_active != NULL)
       
  1672                 app_active = gui_data->host_callbacks.is_app_active();
       
  1673 
       
  1674             if (app_active)
       
  1675                 gui_grab_start();
       
  1676 #endif
       
  1677         } else {
       
  1678             gui_loaded_grab_end();
       
  1679         }
       
  1680     }
       
  1681 }
       
  1682 
       
  1683 static void gui_loaded_notify_new_guest_cursor(void)
       
  1684 {
       
  1685     /* DFG: DANGER, this call also invokes show_cursor() */
       
  1686     if (gui_data->guest_cursor &&
       
  1687             (gui_grabbing() /*|| kbd_mouse_is_absolute() || absolute_enabled*/))
       
  1688         gui_data->host_callbacks.turn_cursor_on(GUI_CURSOR_GUEST_SPRITE);
       
  1689 }
       
  1690 
       
  1691 static void gui_loaded_notify_input_focus_lost(void)
       
  1692 {
       
  1693     if (gui_grabbing())
       
  1694         gui_loaded_grab_end();
       
  1695 }
       
  1696 
       
  1697 static void gui_loaded_notify_app_focus(int gain)
       
  1698 {
       
  1699     gui_unloaded_notify_app_focus(gain);
       
  1700 }
       
  1701 
       
  1702 
       
  1703 /**************************************************************************/
       
  1704 
       
  1705 const gui_input_table_t input_tables[2] = {
       
  1706     {
       
  1707         gui_unloaded_notify_toggle_fullscreen,
       
  1708         gui_unloaded_notify_toggle_grabmode,
       
  1709         gui_unloaded_notify_mouse_motion,
       
  1710         gui_unloaded_notify_mouse_button,
       
  1711         gui_unloaded_notify_mouse_warp,
       
  1712         gui_unloaded_notify_new_guest_cursor,
       
  1713         gui_unloaded_notify_input_focus_lost,
       
  1714         gui_unloaded_notify_app_focus,
       
  1715     },
       
  1716     {
       
  1717         gui_loaded_notify_toggle_fullscreen,
       
  1718         gui_loaded_notify_toggle_grabmode,
       
  1719         gui_loaded_notify_mouse_motion,
       
  1720         gui_loaded_notify_mouse_button,
       
  1721         gui_loaded_notify_mouse_warp,
       
  1722         gui_loaded_notify_new_guest_cursor,
       
  1723         gui_loaded_notify_input_focus_lost,
       
  1724         gui_loaded_notify_app_focus,
       
  1725     },
       
  1726 };
       
  1727 
       
  1728 static void gui_set_input_state(enum gui_input_state_t input_state)
       
  1729 {
       
  1730     gui_data->input_table = &input_tables[input_state];
       
  1731 }
       
  1732