|
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 |