1 /////////////////////////////////////////////////////////////////////////
2 // $Id: svga.cc,v 1.17 2008/03/06 21:15:40 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2 of the License, or (at your option) any later version.
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
22 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
23 // is used to know when we are exporting symbols and when we are importing.
31 #include </usr/include/vga.h>
33 #include <vgakeyboard.h>
36 #include "font/vga.bitmap.h"
37 //#include "icon_bochs.h"
39 class bx_svga_gui_c
: public bx_gui_c
{
42 DECLARE_GUI_VIRTUAL_METHODS()
43 virtual void set_display_mode (disp_mode_t newmode
);
46 // declare one instance of the gui object and call macro to insert the
48 static bx_svga_gui_c
*theGui
= NULL
;
50 IMPLEMENT_GUI_PLUGIN_CODE(svga
)
52 #define LOG_THIS theGui->
54 static unsigned res_x
, res_y
;
55 static unsigned fontwidth
, fontheight
;
56 static unsigned tilewidth
, tileheight
;
57 static unsigned char vgafont
[256 * 16];
59 GraphicsContext
*screen
= NULL
;
60 static int save_vga_mode
;
61 static int save_vga_pal
[256 * 3];
62 static Bit8u fontbuffer
[0x2000];
64 static bx_bool ctrll_pressed
= 0;
65 static unsigned int text_rows
=25, text_cols
=80;
66 static unsigned prev_cursor_x
=0;
67 static unsigned prev_cursor_y
=0;
69 void keyboard_handler(int scancode
, int press
);
70 void mouse_handler(int button
, int dx
, int dy
, int dz
,
71 int drx
, int dry
, int drz
);
73 unsigned char reverse_byteorder(unsigned char b
)
75 unsigned char ret
= 0;
77 for (unsigned i
=0;i
<8;i
++){
78 ret
|= (b
& 0x01) << (7 - i
);
84 void create_vga_font()
86 memcpy(vgafont
, bx_vgafont
, sizeof(bx_vgafont
));
88 for (unsigned i
=0;i
< sizeof(bx_vgafont
);i
++) {
89 vgafont
[i
] = reverse_byteorder(vgafont
[i
]);
93 bx_svga_gui_c::bx_svga_gui_c()
98 void bx_svga_gui_c::specific_init(
103 unsigned header_bar_y
)
105 tilewidth
= x_tilesize
;
106 tileheight
= y_tilesize
;
110 LOG_THIS
setonoff(LOGLEV_PANIC
, ACT_FATAL
);
111 BX_PANIC (("Unable to initialize SVGAlib"));
115 screen
= gl_allocatecontext();
119 dimension_update(640,400);
121 gl_setfont(fontwidth
, fontheight
, (void *)vgafont
);
122 gl_setwritemode(FONT_COMPRESSED
);
125 keyboard_seteventhandler((__keyboard_handler
) keyboard_handler
);
127 vga_setmousesupport(1);
128 mouse_seteventhandler((__mouse_handler
) mouse_handler
);
129 if (vga_ext_set(VGA_EXT_AVAILABLE
, VGA_AVAIL_FLAGS
) & VGA_CLUT8
) {
130 vga_ext_set(VGA_EXT_SET
, VGA_CLUT8
);
133 // Save settings to prepare for mode transition in set_display_mode.
134 // If DISP_MODE_SIM is called first, these values will be used.
135 save_vga_mode
= vga_getcurrentmode();
136 vga_getpalvec(0, 256, save_vga_pal
);
139 void bx_svga_gui_c::text_update(
142 unsigned long cursor_x
,
143 unsigned long cursor_y
,
144 bx_vga_tminfo_t tm_info
)
146 Bit8u
*old_line
, *new_line
;
147 unsigned int curs
, hchars
, i
, j
, offset
, rows
, x
, y
;
150 bx_bool force_update
= 0, blink_state
, blink_mode
;
151 int text_palette
[16];
153 // first check if the screen needs to be redrawn completely
154 blink_mode
= (tm_info
.blink_flags
& BX_TEXT_BLINK_MODE
) > 0;
155 blink_state
= (tm_info
.blink_flags
& BX_TEXT_BLINK_STATE
) > 0;
157 if (tm_info
.blink_flags
& BX_TEXT_BLINK_TOGGLE
)
160 if (charmap_updated
) {
161 BX_INFO(("charmap update. Font Height is %d", fontheight
));
162 for (unsigned c
= 0; c
<256; c
++) {
163 if (char_changed
[c
]) {
165 for(i
=0; i
<fontheight
; i
++) {
166 fontbuffer
[j
++] = vga_charmap
[(c
<<5)+i
];
171 gl_setfont(fontwidth
, fontheight
, (void *)fontbuffer
);
175 for (i
=0; i
<16; i
++) {
176 text_palette
[i
] = DEV_vga_get_actl_pal_idx(i
);
179 // invalidate character at previous and new cursor location
180 if((prev_cursor_y
< text_rows
) && (prev_cursor_x
< text_cols
)) {
181 curs
= prev_cursor_y
* tm_info
.line_offset
+ prev_cursor_x
* 2;
182 old_text
[curs
] = ~new_text
[curs
];
184 if((tm_info
.cs_start
<= tm_info
.cs_end
) && (tm_info
.cs_start
< fontheight
) &&
185 (cursor_y
< text_rows
) && (cursor_x
< text_cols
)) {
186 curs
= cursor_y
* tm_info
.line_offset
+ cursor_x
* 2;
187 old_text
[curs
] = ~new_text
[curs
];
199 offset
= y
* tm_info
.line_offset
;
201 if (force_update
|| (old_text
[0] != new_text
[0])
202 || (old_text
[1] != new_text
[1])) {
204 fg
= text_palette
[new_text
[1] & 0x0F];
206 bg
= text_palette
[(new_text
[1] & 0x70) >> 4];
207 if (!blink_state
&& (new_text
[1] & 0x80))
210 bg
= text_palette
[(new_text
[1] & 0xF0) >> 4];
212 if (offset
== curs
) {
213 gl_setfontcolors(fg
, bg
);
215 gl_setfontcolors(bg
, fg
);
217 gl_write(x
* fontwidth
, y
* fontheight
, s
);
225 new_text
= new_line
+ tm_info
.line_offset
;
226 old_text
= old_line
+ tm_info
.line_offset
;
229 prev_cursor_x
= cursor_x
;
230 prev_cursor_y
= cursor_y
;
233 int bx_svga_gui_c::get_clipboard_text(Bit8u
**bytes
, Bit32s
*nbytes
)
238 int bx_svga_gui_c::set_clipboard_text(char *text_snapshot
, Bit32u len
)
243 void bx_svga_gui_c::graphics_tile_update(Bit8u
*snapshot
, unsigned x
, unsigned y
)
245 if ((y
+ tileheight
) > res_y
) {
246 gl_putbox(x
, y
, tilewidth
, (res_y
- y
), snapshot
);
248 gl_putbox(x
, y
, tilewidth
, tileheight
, snapshot
);
252 static Bit32u
vga_to_bx_key(int key
)
256 case SCANCODE_ESCAPE
: return BX_KEY_ESC
;
257 case SCANCODE_1
: return BX_KEY_1
;
258 case SCANCODE_2
: return BX_KEY_2
;
259 case SCANCODE_3
: return BX_KEY_3
;
260 case SCANCODE_4
: return BX_KEY_4
;
261 case SCANCODE_5
: return BX_KEY_5
;
262 case SCANCODE_6
: return BX_KEY_6
;
263 case SCANCODE_7
: return BX_KEY_7
;
264 case SCANCODE_8
: return BX_KEY_8
;
265 case SCANCODE_9
: return BX_KEY_9
;
266 case SCANCODE_0
: return BX_KEY_0
;
268 case SCANCODE_MINUS
: return BX_KEY_MINUS
;
269 case SCANCODE_EQUAL
: return BX_KEY_EQUALS
;
270 case SCANCODE_TAB
: return BX_KEY_TAB
;
271 case SCANCODE_BACKSPACE
: return BX_KEY_BACKSPACE
;
273 case SCANCODE_Q
: return BX_KEY_Q
;
274 case SCANCODE_W
: return BX_KEY_W
;
275 case SCANCODE_E
: return BX_KEY_E
;
276 case SCANCODE_R
: return BX_KEY_R
;
277 case SCANCODE_T
: return BX_KEY_T
;
278 case SCANCODE_Y
: return BX_KEY_Y
;
279 case SCANCODE_U
: return BX_KEY_U
;
280 case SCANCODE_I
: return BX_KEY_I
;
281 case SCANCODE_O
: return BX_KEY_O
;
282 case SCANCODE_P
: return BX_KEY_P
;
284 case SCANCODE_BRACKET_LEFT
: return BX_KEY_LEFT_BRACKET
;
285 case SCANCODE_BRACKET_RIGHT
: return BX_KEY_RIGHT_BRACKET
;
287 case SCANCODE_ENTER
: return BX_KEY_ENTER
;
288 case SCANCODE_LEFTCONTROL
:
290 return BX_KEY_CTRL_L
;
292 case SCANCODE_A
: return BX_KEY_A
;
293 case SCANCODE_S
: return BX_KEY_S
;
294 case SCANCODE_D
: return BX_KEY_D
;
295 case SCANCODE_F
: return BX_KEY_F
;
296 case SCANCODE_G
: return BX_KEY_G
;
297 case SCANCODE_H
: return BX_KEY_H
;
298 case SCANCODE_J
: return BX_KEY_J
;
299 case SCANCODE_K
: return BX_KEY_K
;
300 case SCANCODE_L
: return BX_KEY_L
;
302 case SCANCODE_SEMICOLON
: return BX_KEY_SEMICOLON
;
303 case SCANCODE_APOSTROPHE
: return BX_KEY_SINGLE_QUOTE
;
304 case SCANCODE_GRAVE
: return BX_KEY_GRAVE
;
306 case SCANCODE_LEFTSHIFT
: return BX_KEY_SHIFT_L
;
307 case SCANCODE_BACKSLASH
: return BX_KEY_BACKSLASH
;
309 case SCANCODE_Z
: return BX_KEY_Z
;
310 case SCANCODE_X
: return BX_KEY_X
;
311 case SCANCODE_C
: return BX_KEY_C
;
312 case SCANCODE_V
: return BX_KEY_V
;
313 case SCANCODE_B
: return BX_KEY_B
;
314 case SCANCODE_N
: return BX_KEY_N
;
315 case SCANCODE_M
: return BX_KEY_M
;
317 case SCANCODE_COMMA
: return BX_KEY_COMMA
;
318 case SCANCODE_PERIOD
: return BX_KEY_PERIOD
;
319 case SCANCODE_SLASH
: return BX_KEY_SLASH
;
321 case SCANCODE_RIGHTSHIFT
: return BX_KEY_SHIFT_R
;
322 case SCANCODE_KEYPADMULTIPLY
: return BX_KEY_KP_MULTIPLY
;
324 case SCANCODE_LEFTALT
: return BX_KEY_ALT_L
;
325 case SCANCODE_SPACE
: return BX_KEY_SPACE
;
326 case SCANCODE_CAPSLOCK
: return BX_KEY_CAPS_LOCK
;
328 case SCANCODE_F1
: return BX_KEY_F1
;
329 case SCANCODE_F2
: return BX_KEY_F2
;
330 case SCANCODE_F3
: return BX_KEY_F3
;
331 case SCANCODE_F4
: return BX_KEY_F4
;
332 case SCANCODE_F5
: return BX_KEY_F5
;
333 case SCANCODE_F6
: return BX_KEY_F6
;
334 case SCANCODE_F7
: return BX_KEY_F7
;
335 case SCANCODE_F8
: return BX_KEY_F8
;
336 case SCANCODE_F9
: return BX_KEY_F9
;
337 case SCANCODE_F10
: return BX_KEY_F10
;
339 case SCANCODE_NUMLOCK
: return BX_KEY_NUM_LOCK
;
340 case SCANCODE_SCROLLLOCK
: return BX_KEY_SCRL_LOCK
;
342 case SCANCODE_KEYPAD7
: return BX_KEY_KP_HOME
;
343 case SCANCODE_KEYPAD8
: return BX_KEY_KP_UP
;
344 case SCANCODE_KEYPAD9
: return BX_KEY_KP_PAGE_UP
;
345 case SCANCODE_KEYPADMINUS
: return BX_KEY_KP_SUBTRACT
;
346 case SCANCODE_KEYPAD4
: return BX_KEY_KP_LEFT
;
347 case SCANCODE_KEYPAD5
: return BX_KEY_KP_5
;
348 case SCANCODE_KEYPAD6
: return BX_KEY_KP_RIGHT
;
349 case SCANCODE_KEYPADPLUS
: return BX_KEY_KP_ADD
;
350 case SCANCODE_KEYPAD1
: return BX_KEY_KP_END
;
351 case SCANCODE_KEYPAD2
: return BX_KEY_KP_DOWN
;
352 case SCANCODE_KEYPAD3
: return BX_KEY_KP_PAGE_DOWN
;
353 case SCANCODE_KEYPAD0
: return BX_KEY_KP_INSERT
;
354 // case SCANCODE_KEYPADPERIOD: return BX_KEY_KP_; /* ??? */
356 // case SCANCODE_LESS: return BX_KEY_KP_LESS; /* ??? */
358 case SCANCODE_F11
: return BX_KEY_F11
;
359 case SCANCODE_F12
: return BX_KEY_F12
;
361 case SCANCODE_KEYPADENTER
: return BX_KEY_KP_ENTER
;
362 case SCANCODE_RIGHTCONTROL
: return BX_KEY_CTRL_R
;
363 case SCANCODE_KEYPADDIVIDE
: return BX_KEY_KP_DIVIDE
;
364 case SCANCODE_PRINTSCREEN
: return BX_KEY_PRINT
;
365 case SCANCODE_RIGHTALT
: return BX_KEY_ALT_R
;
366 case SCANCODE_BREAK
: return BX_KEY_PAUSE
;
368 case SCANCODE_HOME
: return BX_KEY_HOME
;
369 case SCANCODE_CURSORBLOCKUP
: return BX_KEY_UP
;
370 case SCANCODE_PAGEUP
: return BX_KEY_PAGE_UP
;
371 case SCANCODE_CURSORBLOCKLEFT
: return BX_KEY_LEFT
;
372 case SCANCODE_CURSORBLOCKRIGHT
: return BX_KEY_RIGHT
;
373 case SCANCODE_END
: return BX_KEY_END
;
374 case SCANCODE_CURSORBLOCKDOWN
: return BX_KEY_DOWN
;
375 case SCANCODE_PAGEDOWN
: return BX_KEY_PAGE_DOWN
;
376 case SCANCODE_INSERT
: return BX_KEY_INSERT
;
377 case SCANCODE_REMOVE
: return BX_KEY_DELETE
;
379 case SCANCODE_RIGHTWIN
: return BX_KEY_WIN_R
;
380 case SCANCODE_LEFTWIN
: return BX_KEY_WIN_L
;
386 void keyboard_handler(int scancode
, int press
)
388 if (scancode
!= SCANCODE_F12
) {
389 int bx_key
= vga_to_bx_key(scancode
);
393 key_state
= BX_KEY_PRESSED
;
395 key_state
= BX_KEY_RELEASED
;
398 DEV_kbd_gen_scancode(bx_key
| key_state
);
400 BX_INFO(("F12 pressed"));
401 // show runtime options menu, which uses stdin/stdout
402 SIM
->configuration_interface (NULL
, CI_RUNTIME_CONFIG
);
406 void mouse_handler(int button
, int dx
, int dy
, int dz
,
407 int drx
, int dry
, int drz
)
411 if (button
& MOUSE_LEFTBUTTON
) {
414 if (button
& MOUSE_RIGHTBUTTON
) {
417 if (button
& MOUSE_MIDDLEBUTTON
) {
420 if (ctrll_pressed
&& ((buttons
== 0x04) || (buttons
== 0x05))) {
421 bx_bool old
= SIM
->get_param_bool(BXPN_MOUSE_ENABLED
)->get();
422 SIM
->get_param_bool(BXPN_MOUSE_ENABLED
)->set(!old
);
424 DEV_mouse_motion((int) (0.25 * dx
), (int) -(0.25 * dy
), buttons
);
428 void bx_svga_gui_c::handle_events(void)
431 keyboard_clearstate();
435 void bx_svga_gui_c::flush(void)
437 gl_copyscreen(screen
);
440 void bx_svga_gui_c::clear_screen(void)
445 bx_bool
bx_svga_gui_c::palette_change(
451 if(index
> 255) return 0;
453 // without VGA_CLUT8 extension we have only 6 bits for each r,g,b value
454 if (!clut8
&& (red
> 63 || green
> 63 || blue
> 63)) {
460 vga_setpalette(index
, red
, green
, blue
);
466 void bx_svga_gui_c::dimension_update(
476 BX_PANIC(("%d bpp graphics mode not supported yet", bpp
));
480 text_cols
= x
/ fwidth
;
481 text_rows
= y
/ fheight
;
482 fontheight
= fheight
;
489 if ((x
== res_x
) && (y
== res_y
)) return;
491 if (x
== 640 && y
== 480) {
492 newmode
= G640x480x256
;
493 } else if (x
== 640 && y
== 400) {
494 newmode
= G640x400x256
;
495 } else if (x
== 800 && y
== 600) {
496 newmode
= G800x600x256
;
497 } else if (x
== 1024 && y
== 768) {
498 newmode
= G1024x768x256
;
501 if (!vga_hasmode(newmode
)) {
502 newmode
= G640x480x256
; // trying "default" mode...
505 vga_getpalvec(0, 256, save_vga_pal
);
506 if (vga_setmode(newmode
) != 0)
508 LOG_THIS
setonoff(LOGLEV_PANIC
, ACT_FATAL
);
509 BX_PANIC (("Unable to set requested videomode: %ix%i", x
, y
));
512 gl_setcontextvga(newmode
);
513 gl_getcontext(screen
);
514 gl_setcontextvgavirtual(newmode
);
515 vga_setpalvec(0, 256, save_vga_pal
);
516 save_vga_mode
= newmode
;
523 unsigned bx_svga_gui_c::create_bitmap(
524 const unsigned char *bmap
,
532 unsigned bx_svga_gui_c::headerbar_bitmap(
540 void bx_svga_gui_c::replace_bitmap(unsigned hbar_id
, unsigned bmap_id
)
544 void bx_svga_gui_c::show_headerbar(void)
549 void bx_svga_gui_c::mouse_enabled_changed_specific (bx_bool val
)
554 void headerbar_click(int x
)
558 void bx_svga_gui_c::exit(void)
565 void bx_svga_gui_c::set_display_mode (disp_mode_t newmode
)
567 // if no mode change, do nothing.
568 if (disp_mode
== newmode
) return;
569 // remember the display mode for next time
572 case DISP_MODE_CONFIG
:
573 BX_DEBUG (("switch to configuration mode (back to console)"));
574 // remember old values and switch to text mode
575 save_vga_mode
= vga_getcurrentmode();
576 vga_getpalvec(0, 256, save_vga_pal
);
581 BX_DEBUG (("switch to simulation mode (fullscreen)"));
583 keyboard_seteventhandler((__keyboard_handler
) keyboard_handler
);
584 vga_setmode(save_vga_mode
);
585 vga_setpalvec(0, 256, save_vga_pal
);
590 #endif /* if BX_WITH_SVGA */