links/svgalib.c

2403 lines
60 KiB
C

/* svgalib.c
* (c) 2000-2002 Karel 'Clock' Kulhavy
* This file is a part of the Links program, released under GPL.
*
* This does graphics driver of svgalib, svgalib mouse.
* This doesn't do svgalib keyboard.
*/
#include "cfg.h"
#ifdef GRDRV_SVGALIB
#include "links.h"
#include "bits.h"
#include <vga.h>
#include <vgamouse.h>
#include "arrow.inc"
struct irgb {
unsigned rgb[3];
};
static struct itrm *svgalib_kbd;
extern struct graphics_driver svga_driver;
static int mouse_x, mouse_y, mouse_buttons; /* For tracking the state of the mouse */
static int background_x, background_y; /* Where was the mouse background taken from */
static unsigned char *mouse_buffer, *background_buffer, *new_background_buffer;
static struct graphics_device *mouse_graphics_device;
static int global_mouse_hidden;
static long mouse_black, mouse_white; /* Mouse arrow pointer colors */
static int (* mouse_getscansegment)(unsigned char *, int, int, int);
static int (* mouse_drawscansegment)(unsigned char *, int, int, int);
static unsigned char mouse_works = 0;
static unsigned char *svga_driver_param; /* NULL by default */
static int vga_mode; /* The mode that has been selected */
static int mouse_aggregate_flag, mouse_aggregate_action;
static int flags = 0; /* OR-ed 1: running in background
* 2: vga_block()-ed
*/
#ifndef __SPAD__
static struct timer *svgalib_timer_id;
#endif
/*---------------------------LIMITATIONS---------------------------------------*/
/* pixel_set_paged works only for <=8 bytes per pixel.
* Doesn't work on video cards which have 1 pixel spanning more that 65536 bytes! ( :-) )
* vga_linewidth%vga_bytes must be zero.
* The bitmaps have all consecutive data. No vidram mallocing is performed.
*/
/*------------------------STRUCTURES-------------------------------------------*/
struct modeline{
char *name;
int number;
};
/*-------------- GLOBAL VARIABLES --------------------------------------------*/
#define NUMBER_OF_DEVICES 10
#define TEST_INACTIVITY if (dev != current_virtual_device || flags) return;
#define TEST_INACTIVITY_0 if (dev != current_virtual_device || flags) return 0;
#define RECTANGLES_INTERSECT(xl0, xh0, xl1, xh1, yl0, yh0, yl1, yh1) (\
(xl0)<(xh1)\
&& (xl1)<(xh0)\
&& (yl0)<(yh1)\
&& (yl1)<(yh0))
#define TEST_MOUSE(xl,xh,yl,yh) if (RECTANGLES_INTERSECT(\
(xl),(xh),\
background_x,background_x+arrow_width,\
(yl),(yh),\
background_y,background_y+arrow_height)\
&& !global_mouse_hidden){\
mouse_hidden=1;\
hide_mouse();\
}else mouse_hidden=0;
#define END_MOUSE if (mouse_hidden) show_mouse();
/* Actual vga mode definition */
static int vga_linewidth; /* Prepared out from vga_getmodeinfo */
static int xsize, ysize; /* Prepared out from vga_getmodeinfo */
static int vga_bytes; /* Prepared out from vga_getmodeinfo */
static int vga_colors; /* Prepared out from vga_getmodeinfo */
static int vga_misordered; /* Prepared out from vga_getmodeinfo */
static int vga_linear; /* 1 linear mode, 0 nonlinear mode (paged) */
static int palette_depth; /* 6 for normal VGA, 8 for VGA which supports 8 bit DAC */
static int accel_avail; /* Which accel fns are available */
static int do_sync; /* Tells the "normal" memory operations (those
* that do not use accelerator) to do
* vga_accel(ACCEL_SYNC) before writing into the
* memory.
*/
static int vga_page=-1;
static int mode_x; /* 1 if mode_X organization is set up */
static int fb_pixelsize; /* Number of bytes per pixel in bitmap */
static unsigned char *my_graph_mem;
static unsigned char *scroll_buffer = NULL; /* For paged scrolling only */
static struct modeline modes[]={
#ifdef G320x200x16
{"320x200x16", G320x200x16 },
#endif
#ifdef G320x200x256
{"320x200x256", G320x200x256 },
#endif
#ifdef G320x200x32K
{"320x200x32K", G320x200x32K },
#endif
#ifdef G320x200x64K
{"320x200x64K", G320x200x64K },
#endif
#ifdef G320x200x16M
{"320x200x16M", G320x200x16M },
#endif
#ifdef G320x200x16M32
{"320x200x16M32", G320x200x16M32 },
#endif
#ifdef G320x240x256
{"320x240x256", G320x240x256 },
#endif
#ifdef G320x240x32K
{"320x240x32K", G320x240x32K },
#endif
#ifdef G320x240x64K
{"320x240x64K", G320x240x64K },
#endif
#ifdef G320x240x16M
{"320x240x16M", G320x240x16M },
#endif
#ifdef G320x240x16M32
{"320x240x16M32", G320x240x16M32 },
#endif
#ifdef G320x400x256
{"320x400x256", G320x400x256 },
#endif
#ifdef G320x400x32K
{"320x400x32K", G320x400x32K },
#endif
#ifdef G320x400x64K
{"320x400x64K", G320x400x64K },
#endif
#ifdef G320x400x16M
{"320x400x16M", G320x400x16M },
#endif
#ifdef G320x400x16M32
{"320x400x16M32", G320x400x16M32 },
#endif
#ifdef G320x480x256
{"320x480x256", G320x480x256 },
#endif
#ifdef G320x480x32K
{"320x480x32K", G320x480x32K },
#endif
#ifdef G320x480x64K
{"320x480x64K", G320x480x64K },
#endif
#ifdef G320x480x16M
{"320x480x16M", G320x480x16M },
#endif
#ifdef G320x480x16M32
{"320x480x16M32", G320x480x16M32 },
#endif
#ifdef G360x480x256
{"360x480x256", G360x480x256 },
#endif
#ifdef G400x300x256
{"400x300x256", G400x300x256 },
#endif
#ifdef G400x300x32K
{"400x300x32K", G400x300x32K },
#endif
#ifdef G400x300x64K
{"400x300x64K", G400x300x64K },
#endif
#ifdef G400x300x16M
{"400x300x16M", G400x300x16M },
#endif
#ifdef G400x300x16M32
{"400x300x16M32", G400x300x16M32 },
#endif
#ifdef G400x600x256
{"400x600x256", G400x600x256 },
#endif
#ifdef G400x600x32K
{"400x600x32K", G400x600x32K },
#endif
#ifdef G400x600x64K
{"400x600x64K", G400x600x64K },
#endif
#ifdef G400x600x16M
{"400x600x16M", G400x600x16M },
#endif
#ifdef G400x600x16M32
{"400x600x16M32", G400x600x16M32 },
#endif
#ifdef G512x384x256
{"512x384x256", G512x384x256 },
#endif
#ifdef G512x384x32K
{"512x384x32K", G512x384x32K },
#endif
#ifdef G512x384x64K
{"512x384x64K", G512x384x64K },
#endif
#ifdef G512x384x16M
{"512x384x16M", G512x384x16M },
#endif
#ifdef G512x384x16M32
{"512x384x16M32", G512x384x16M32 },
#endif
#ifdef G512x480x256
{"512x480x256", G512x480x256 },
#endif
#ifdef G512x480x32K
{"512x480x32K", G512x480x32K },
#endif
#ifdef G512x480x64K
{"512x480x64K", G512x480x64K },
#endif
#ifdef G512x480x16M
{"512x480x16M", G512x480x16M },
#endif
#ifdef G512x480x16M32
{"512x480x16M32", G512x480x16M32 },
#endif
#ifdef G640x200x16
{"640x200x16", G640x200x16 },
#endif
#ifdef G640x350x16
{"640x350x16", G640x350x16 },
#endif
#ifdef G640x400x256
{"640x400x256", G640x400x256 },
#endif
#ifdef G640x400x32K
{"640x400x32K", G640x400x32K },
#endif
#ifdef G640x400x64K
{"640x400x64K", G640x400x64K },
#endif
#ifdef G640x400x16M
{"640x400x16M", G640x400x16M },
#endif
#ifdef G640x400x16M32
{"640x400x16M32", G640x400x16M32 },
#endif
#ifdef G640x480x16
{"640x480x16", G640x480x16 },
#endif
#ifdef G640x480x256
{"640x480x256", G640x480x256 },
#endif
#ifdef G640x480x32K
{"640x480x32K", G640x480x32K },
#endif
#ifdef G640x480x64K
{"640x480x64K", G640x480x64K },
#endif
#ifdef G640x480x16M
{"640x480x16M", G640x480x16M },
#endif
#ifdef G640x480x16M32
{"640x480x16M32", G640x480x16M32 },
#endif
#ifdef G720x540x256
{"720x540x256", G720x540x256 },
#endif
#ifdef G720x540x32K
{"720x540x32K", G720x540x32K },
#endif
#ifdef G720x540x64K
{"720x540x64K", G720x540x64K },
#endif
#ifdef G720x540x16M
{"720x540x16M", G720x540x16M },
#endif
#ifdef G720x540x16M32
{"720x540x16M32", G720x540x16M32 },
#endif
#ifdef G800x600x16
{"800x600x16", G800x600x16 },
#endif
#ifdef G800x600x256
{"800x600x256", G800x600x256 },
#endif
#ifdef G800x600x32K
{"800x600x32K", G800x600x32K },
#endif
#ifdef G800x600x64K
{"800x600x64K", G800x600x64K },
#endif
#ifdef G800x600x16M
{"800x600x16M", G800x600x16M },
#endif
#ifdef G800x600x16M32
{"800x600x16M32", G800x600x16M32 },
#endif
#ifdef G848x480x256
{"848x480x256", G848x480x256 },
#endif
#ifdef G848x480x32K
{"848x480x32K", G848x480x32K },
#endif
#ifdef G848x480x64K
{"848x480x64K", G848x480x64K },
#endif
#ifdef G848x480x16M
{"848x480x16M", G848x480x16M },
#endif
#ifdef G848x480x16M32
{"848x480x16M32", G848x480x16M32 },
#endif
#ifdef G960x720x256
{"960x720x256", G960x720x256 },
#endif
#ifdef G960x720x32K
{"960x720x32K", G960x720x32K },
#endif
#ifdef G960x720x64K
{"960x720x64K", G960x720x64K },
#endif
#ifdef G960x720x16M
{"960x720x16M", G960x720x16M },
#endif
#ifdef G960x720x16M32
{"960x720x16M32", G960x720x16M32 },
#endif
#ifdef G1024x768x16
{"1024x768x16", G1024x768x16 },
#endif
#ifdef G1024x768x256
{"1024x768x256", G1024x768x256 },
#endif
#ifdef G1024x768x32K
{"1024x768x32K", G1024x768x32K },
#endif
#ifdef G1024x768x64K
{"1024x768x64K", G1024x768x64K },
#endif
#ifdef G1024x768x16M
{"1024x768x16M", G1024x768x16M },
#endif
#ifdef G1024x768x16M32
{"1024x768x16M32", G1024x768x16M32 },
#endif
#ifdef G1072x600x256
{"1072x600x256", G1072x600x256 },
#endif
#ifdef G1072x600x32K
{"1072x600x32K", G1072x600x32K },
#endif
#ifdef G1072x600x64K
{"1072x600x64K", G1072x600x64K },
#endif
#ifdef G1072x600x16M
{"1072x600x16M", G1072x600x16M },
#endif
#ifdef G1072x600x16M32
{"1072x600x16M32", G1072x600x16M32 },
#endif
#ifdef G1152x864x16
{"1152x864x16", G1152x864x16 },
#endif
#ifdef G1152x864x256
{"1152x864x256", G1152x864x256 },
#endif
#ifdef G1152x864x32K
{"1152x864x32K", G1152x864x32K },
#endif
#ifdef G1152x864x64K
{"1152x864x64K", G1152x864x64K },
#endif
#ifdef G1152x864x16M
{"1152x864x16M", G1152x864x16M },
#endif
#ifdef G1152x864x16M32
{"1152x864x16M32", G1152x864x16M32 },
#endif
#ifdef G1280x720x256
{"1280x720x256", G1280x720x256 },
#endif
#ifdef G1280x720x32K
{"1280x720x32K", G1280x720x32K },
#endif
#ifdef G1280x720x64K
{"1280x720x64K", G1280x720x64K },
#endif
#ifdef G1280x720x16M
{"1280x720x16M", G1280x720x16M },
#endif
#ifdef G1280x720x16M32
{"1280x720x16M32", G1280x720x16M32 },
#endif
#ifdef G1280x1024x16
{"1280x1024x16", G1280x1024x16 },
#endif
#ifdef G1280x1024x256
{"1280x1024x256", G1280x1024x256 },
#endif
#ifdef G1280x1024x32K
{"1280x1024x32K", G1280x1024x32K },
#endif
#ifdef G1280x1024x64K
{"1280x1024x64K", G1280x1024x64K },
#endif
#ifdef G1280x1024x16M
{"1280x1024x16M", G1280x1024x16M },
#endif
#ifdef G1280x1024x16M32
{"1280x1024x16M32", G1280x1024x16M32 },
#endif
#ifdef G1360x768x256
{"1360x768x256", G1360x768x256 },
#endif
#ifdef G1360x768x32K
{"1360x768x32K", G1360x768x32K },
#endif
#ifdef G1360x768x64K
{"1360x768x64K", G1360x768x64K },
#endif
#ifdef G1360x768x16M
{"1360x768x16M", G1360x768x16M },
#endif
#ifdef G1360x768x16M32
{"1360x768x16M32", G1360x768x16M32 },
#endif
#ifdef G1600x1200x16
{"1600x1200x16", G1600x1200x16 },
#endif
#ifdef G1600x1200x256
{"1600x1200x256", G1600x1200x256 },
#endif
#ifdef G1600x1200x32K
{"1600x1200x32K", G1600x1200x32K },
#endif
#ifdef G1600x1200x64K
{"1600x1200x64K", G1600x1200x64K },
#endif
#ifdef G1600x1200x16M
{"1600x1200x16M", G1600x1200x16M },
#endif
#ifdef G1600x1200x16M32
{"1600x1200x16M32", G1600x1200x16M32 },
#endif
#ifdef G1800x1012x256
{"1800x1012x256", G1800x1012x256 },
#endif
#ifdef G1800x1012x32K
{"1800x1012x32K", G1800x1012x32K },
#endif
#ifdef G1800x1012x64K
{"1800x1012x64K", G1800x1012x64K },
#endif
#ifdef G1800x1012x16M
{"1800x1012x16M", G1800x1012x16M },
#endif
#ifdef G1800x1012x16M32
{"1800x1012x16M32", G1800x1012x16M32 },
#endif
#ifdef G1920x1080x256
{"1920x1080x256", G1920x1080x256 },
#endif
#ifdef G1920x1080x32K
{"1920x1080x32K", G1920x1080x32K },
#endif
#ifdef G1920x1080x64K
{"1920x1080x64K", G1920x1080x64K },
#endif
#ifdef G1920x1080x16M
{"1920x1080x16M", G1920x1080x16M },
#endif
#ifdef G1920x1080x16M32
{"1920x1080x16M32", G1920x1080x16M32 },
#endif
#ifdef G1920x1440x256
{"1920x1440x256", G1920x1440x256 },
#endif
#ifdef G1920x1440x32K
{"1920x1440x32K", G1920x1440x32K },
#endif
#ifdef G1920x1440x64K
{"1920x1440x64K", G1920x1440x64K },
#endif
#ifdef G1920x1440x16M
{"1920x1440x16M", G1920x1440x16M },
#endif
#ifdef G1920x1440x16M32
{"1920x1440x16M32", G1920x1440x16M32 },
#endif
#ifdef G2048x1152x256
{"2048x1152x256", G2048x1152x256 },
#endif
#ifdef G2048x1152x32K
{"2048x1152x32K", G2048x1152x32K },
#endif
#ifdef G2048x1152x64K
{"2048x1152x64K", G2048x1152x64K },
#endif
#ifdef G2048x1152x16M
{"2048x1152x16M", G2048x1152x16M },
#endif
#ifdef G2048x1152x16M32
{"2048x1152x16M32", G2048x1152x16M32 },
#endif
#ifdef G2048x1536x256
{"2048x1536x256", G2048x1536x256 },
#endif
#ifdef G2048x1536x32K
{"2048x1536x32K", G2048x1536x32K },
#endif
#ifdef G2048x1536x64K
{"2048x1536x64K", G2048x1536x64K },
#endif
#ifdef G2048x1536x16M
{"2048x1536x16M", G2048x1536x16M },
#endif
#ifdef G2048x1536x16M32
{"2048x1536x16M32", G2048x1536x16M32 },
#endif
};
#include "fbcommon.inc"
/*--------------------------- ROUTINES ---------------------------------------*/
/* Generates these palettes:
* 7 6 5 4 3 2 1 0
* +-----+-----+---+
* | R | G | B |
* +-----+-----+---+
*
*
* 3 2 1 0
* +-+---+-+
* |R| G |B|
* +-+---+-+
*/
static void show_mouse(void);
static void hide_mouse(void);
static void redraw_mouse(void);
/* We must perform a quirkafleg
* This is an empiric magic that ensures
* Good white purity
* Correct rounding and dithering prediction
* And this is the cabbala:
* 063 021 063
* 009 009 021
* 255 085 255
* 036 036 084
*/
static void generate_palette(struct irgb *palette)
{
int a;
unsigned active_colors = (int)vga_colors;
if ((svga_driver.depth & 0x300) == 0x300)
active_colors = 216;
for (a = 0; a < vga_colors; a++) {
q_palette(active_colors, (unsigned)a, (1U << palette_depth) - 1, palette[a].rgb);
}
}
static void set_palette(struct irgb *palette)
{
int r, g, b, c;
for (c = 0; c < vga_colors; c++) {
r = (int)palette[c].rgb[0];
g = (int)palette[c].rgb[1];
b = (int)palette[c].rgb[2];
vga_setpalette(c, r, g, b);
}
}
static void svga_shutdown_driver(void)
{
if (scroll_buffer) mem_free(scroll_buffer);
if (mouse_works){
mem_free(mouse_buffer);
mem_free(background_buffer);
mem_free(new_background_buffer);
svga_driver.shutdown_device(mouse_graphics_device);
mouse_close();
mouse_works=0; /* To keep vga_select disabled */
}
shutdown_virtual_devices();
vga_unlockvc();
#ifndef __SPAD__
kill_timer(svgalib_timer_id);
#endif
vga_setmode_retry:
if (vga_setmode(TEXT) < 0) {
if (out_of_memory(0, NULL, 0))
goto vga_setmode_retry;
fatal_exit("ERROR: vga_setmode failed");
}
svgalib_free_trm(svgalib_kbd);
if (svga_driver_param)mem_free(svga_driver_param);
install_signal_handler(SIGINT, NULL, NULL, 0);
}
static void svga_register_bitmap(struct bitmap *bmp)
{
}
static void svga_unregister_bitmap(struct bitmap *bmp)
{
mem_free(bmp->data);
}
#define SYNC if (do_sync) vga_accel(ACCEL_SYNC);
/* This assures that x, y, xs, ys, data will be sane according to clipping
* rectangle. If nothing lies within this rectangle, the current function
* returns. The data pointer is automatically advanced by this macro to reflect
* the right position to start with inside the bitmap. */
#define CLIP_PREFACE \
int xs, ys;\
unsigned char *data=bmp->data;\
int mouse_hidden;\
\
TEST_INACTIVITY\
CLIP_DRAW_BITMAP\
xs = bmp->x;\
ys = bmp->y;\
if (x+xs>dev->clip.x2) xs=dev->clip.x2-x;\
if (y+ys>dev->clip.y2) ys=dev->clip.y2-y;\
if (dev->clip.x1-x>0){\
xs-=(dev->clip.x1-x);\
data+=fb_pixelsize*(dev->clip.x1-x);\
x=dev->clip.x1;\
}\
if (dev->clip.y1-y>0){\
ys-=(dev->clip.y1-y);\
data+=bmp->skip*(dev->clip.y1-y);\
y=dev->clip.y1;\
}\
/* xs, ys: how much pixels to paint\
* data: where to start painting from\
*/\
TEST_MOUSE(x,x+xs,y,y+ys)
static inline void draw_bitmap_accel(struct graphics_device *dev,
struct bitmap *bmp, int x, int y)
{
CLIP_PREFACE
if (xs*fb_pixelsize==bmp->skip) vga_accel(ACCEL_PUTIMAGE,x,y,xs,ys,data);
else for(;ys;ys--){
vga_accel(ACCEL_PUTIMAGE,x,y,xs,1,data);
data+=bmp->skip;
y++;
}
END_MOUSE
}
static inline void my_setpage(int page)
{
if (vga_page!=page){
vga_page=page;
vga_setpage(page);
}
}
static inline void paged_memcpy(int lina, unsigned char *src, int len)
{
int page = lina >> 16;
int paga = lina & 0xffff;
int remains;
my_setpage(page);
remains = 65536 - paga;
again:
if (remains >= len) {
memcpy_to_fb_inline(my_graph_mem + paga, src, len, 0);
vga_page = page;
return;
}else{
memcpy_to_fb(my_graph_mem + paga, src, remains, 0);
paga = 0;
src += remains;
len -= remains;
remains = 65536;
vga_setpage(++page);
goto again;
}
}
static inline void draw_bitmap_drawscansegment(struct graphics_device *dev, struct bitmap *bmp, int x, int y)
{
int ys0;
CLIP_PREFACE
SYNC
for (ys0=ys;ys0;ys0--){
vga_drawscansegment(data,x,y,xs);
y++;
data+=bmp->skip;
}
END_MOUSE
}
static inline void draw_bitmap_paged(struct graphics_device *dev, struct bitmap *bmp, int x, int y)
{
int scr_start;
size_t copy_len;
CLIP_PREFACE
SYNC
scr_start = y * vga_linewidth + x * vga_bytes;
copy_len = xs * fb_pixelsize;
for(; ys; ys--) {
paged_memcpy(scr_start, data, copy_len);
data += bmp->skip;
scr_start += vga_linewidth;
}
END_MOUSE
}
static inline void draw_bitmap_linear(struct graphics_device *dev,struct bitmap *bmp, int x, int y)
{
unsigned char *scr_start;
size_t copy_len;
CLIP_PREFACE
SYNC
scr_start = my_graph_mem + y * vga_linewidth + x * vga_bytes;
copy_len = xs * fb_pixelsize;
for (; ys; ys--) {
memcpy_to_fb_inline(scr_start, data, copy_len, 0);
data += bmp->skip;
scr_start += vga_linewidth;
}
END_MOUSE
}
/* fill_area: 5,5,10,10 fills in 25 pixels! */
/* This assures that x1, x2, y1, y2 will be sane according to the
* clipping rectangle set up by set_clip_area. If empty region
* results, return from current function occurs. */
#define FILL_CLIP_PREFACE \
int mouse_hidden;\
TEST_INACTIVITY\
CLIP_FILL_AREA\
TEST_MOUSE(x1,x2,y1,y2)
static void fill_area_accel_box(struct graphics_device *dev, int x1, int y1, int x2, int y2, long color)
{
FILL_CLIP_PREFACE
vga_accel(ACCEL_SETFGCOLOR,color);
vga_accel(ACCEL_FILLBOX,x1,y1,x2-x1,y2-y1);
END_MOUSE
}
static void fill_area_accel_lines(struct graphics_device *dev, int x1, int y1, int x2, int y2, long color)
{
int y;
FILL_CLIP_PREFACE
vga_accel(ACCEL_SETFGCOLOR,color);
for (y=y1;y<y2;y++) vga_accel(ACCEL_DRAWLINE,x1,y,x2-1,y);
END_MOUSE
}
static void fill_area_linear(struct graphics_device *dev, int x1, int y1, int x2, int y2, long color)
{
unsigned char *dest;
int y;
FILL_CLIP_PREFACE
SYNC
dest=my_graph_mem+y1*vga_linewidth+x1*vga_bytes;
for (y=y2-y1;y;y--){
pixel_set(dest,(x2-x1)*vga_bytes,&color);
dest+=vga_linewidth;
}
END_MOUSE
}
/* Params are exactly the same as in pixel_set except lina, which is offset from
* my_graph_mem in bytes. Works for every vga_bytes. len is in bytes. len must
* be a whole number of pixels.
*/
static void pixel_set_paged(int lina, int len, void * color)
{
int page=lina>>16; /* Page number */
int paga=lina&0xffff; /* 16-bit address within a page */
int remains=65536-paga; /* How many bytes remain within the page*/
int offset=0; /* Offset inside the pixel */
unsigned char color0[15];
memcpy(color0,color,vga_bytes);
memcpy(color0+vga_bytes,color,vga_bytes-1);
my_setpage(page);
again:
if (remains>=len){
int done=len-len%vga_bytes;
pixel_set(my_graph_mem+paga,done,color0+offset);
paga+=done;
if (done<len)
memcpy_to_fb(my_graph_mem+paga,color0+offset,len-done, 0);
vga_page=page;
return;
}else{
int done=remains-remains%vga_bytes;
pixel_set(my_graph_mem+paga,done,color0+offset);
paga+=done;
if (done<remains)
memcpy_to_fb(my_graph_mem+paga,color0+offset,remains-done, 0);
offset+=(remains-done);
if (offset>=vga_bytes) offset-=vga_bytes;
len-=remains;
remains=65536;
vga_setpage(++page);
paga=0;
goto again;
}
}
static void fill_area_paged(struct graphics_device *dev, int x1, int y1, int x2, int y2, long color)
{
int dest;
int y;
int len;
FILL_CLIP_PREFACE
SYNC
len=(x2-x1)*vga_bytes;
dest=y1*vga_linewidth+x1*vga_bytes;
for (y=y2-y1;y;y--){
pixel_set_paged(dest,len,&color);
dest+=vga_linewidth;
}
END_MOUSE
}
#define HLINE_CLIP_PREFACE \
int mouse_hidden;\
TEST_INACTIVITY\
CLIP_DRAW_HLINE\
TEST_MOUSE(x1,x2,y,y+1)
#define VLINE_CLIP_PREFACE \
int mouse_hidden;\
TEST_INACTIVITY\
CLIP_DRAW_VLINE\
TEST_MOUSE(x,x+1,y1,y2)
static void draw_hline_accel_line(struct graphics_device *dev, int x1, int y, int x2, long color)
{
HLINE_CLIP_PREFACE
vga_accel(ACCEL_SETFGCOLOR,color);
vga_accel(ACCEL_DRAWLINE,x1,y,x2-1,y);
END_MOUSE
}
static void draw_hline_accel_box(struct graphics_device *dev, int x1, int y, int x2, long color)
{
HLINE_CLIP_PREFACE
vga_accel(ACCEL_SETFGCOLOR,color);
vga_accel(ACCEL_FILLBOX,x1,y,x2-x1,1);
END_MOUSE
}
static void draw_vline_accel_line(struct graphics_device *dev, int x, int y1, int y2, long color)
{
VLINE_CLIP_PREFACE
vga_accel(ACCEL_SETFGCOLOR,color);
vga_accel(ACCEL_DRAWLINE,x,y1,x,y2-1);
END_MOUSE
}
static void draw_vline_accel_box(struct graphics_device *dev, int x, int y1, int y2, long color)
{
VLINE_CLIP_PREFACE
vga_accel(ACCEL_SETFGCOLOR,color);
vga_accel(ACCEL_FILLBOX,x,y1,1,y2-y1);
END_MOUSE
}
static void draw_hline_linear(struct graphics_device *dev, int x1, int y, int x2, long color)
{
unsigned char *dest;
HLINE_CLIP_PREFACE
SYNC
dest=my_graph_mem+y*vga_linewidth+x1*vga_bytes;
pixel_set(dest,(x2-x1)*vga_bytes,&color);
END_MOUSE
}
static void draw_vline_linear(struct graphics_device *dev, int x, int y1, int y2, long color)
{
unsigned char *dest;
int y;
VLINE_CLIP_PREFACE
SYNC
dest=my_graph_mem+y1*vga_linewidth+x*vga_bytes;
for (y=(y2-y1);y;y--){
memcpy_to_fb(dest, (unsigned char *)&color, vga_bytes, 0);
dest+=vga_linewidth;
}
END_MOUSE
}
static void draw_hline_paged(struct graphics_device *dev, int x1, int y, int x2, long color)
{
int dest;
int len;
HLINE_CLIP_PREFACE
SYNC
len=(x2-x1)*vga_bytes;
dest=y*vga_linewidth+x1*vga_bytes;
pixel_set_paged(dest,len,&color);
END_MOUSE
}
/* Works only for pixel length = 1 */
static void draw_vline_paged_1(struct graphics_device *dev, int x, int y1, int y2, long color)
{
int dest,n, page,paga,remains;
int byte=*(unsigned char *)&color;
VLINE_CLIP_PREFACE;
SYNC
dest=y1*vga_linewidth+x;
n=y2-y1;
page=dest>>16;
my_setpage(page);
again:
paga=dest&0xffff;
remains=(65535-paga)/vga_linewidth+1;
if (remains>=n){
for (;n;n--){
my_graph_mem[paga]=byte;
paga+=vga_linewidth;
}
vga_page=page;
END_MOUSE
return;
}else{
dest+=remains*vga_linewidth;
n-=remains;
for (;remains;remains--){
my_graph_mem[paga]=byte;
paga+=vga_linewidth;
}
vga_setpage(++page);
goto again;
}
}
#ifdef t2c
/* Works only for pixel length 2 */
static void draw_vline_paged_2(struct graphics_device *dev, int x, int y1, int y2, long color)
{
int dest,page,n,paga,remains;
int word=*(t2c *)memory_barrier((void *)&color);
VLINE_CLIP_PREFACE;
SYNC
dest=y1*vga_linewidth+(x<<1);
n=y2-y1;
page=dest>>16;
my_setpage(page);
again:
paga=dest&0xffff;
remains=(65534-paga)/vga_linewidth+1;
if (remains>=n){
for (;n;n--){
*(t2c *)(my_graph_mem+paga)=word;
paga+=vga_linewidth;
}
vga_page=page;
END_MOUSE
return;
}else{
dest+=remains*vga_linewidth;
n-=remains;
for (;remains;remains--){
*(t2c *)(my_graph_mem+paga)=word;
paga+=vga_linewidth;
}
vga_setpage(++page);
goto again;
}
}
#endif /* #ifdef t2c */
#ifdef t4c
/* Works only for pixel length 4 */
static void draw_vline_paged_4(struct graphics_device *dev, int x, int y1, int y2, long color)
{
unsigned long dest,page,paga,remains,n;
t4c val=*(t4c *)memory_barrier((void *)&color);
VLINE_CLIP_PREFACE;
SYNC
dest=y1*(unsigned long)vga_linewidth+(x<<2);
n=y2-y1;
page=dest>>16;
my_setpage(page);
again:
paga=dest&0xffffUL;
remains=(65532-paga)/vga_linewidth+1;
if (remains>=n){
for (;n;n--){
*(t4c *)(my_graph_mem+paga)=val;
paga+=vga_linewidth;
}
vga_page=page;
END_MOUSE
return;
}else{
dest+=remains*vga_linewidth;
n-=remains;
for (;remains;remains--){
*(t4c *)(my_graph_mem+paga)=color;
paga+=vga_linewidth;
}
vga_setpage(++page);
goto again;
}
}
#endif /*t4c*/
/* Works only for pixel lengths power of two */
static void draw_vline_paged_aligned(struct graphics_device *dev, int x, int y1, int y2, long color)
{
int dest,page,paga,remains,n;
VLINE_CLIP_PREFACE;
SYNC
dest=y1*vga_linewidth+x*vga_bytes;
n=y2-y1;
page=dest>>16;
my_setpage(page);
again:
paga=dest&0xffff;
remains=(65536-paga-vga_bytes)/vga_linewidth+1;
if (remains >= n){
for (; n; n--){
memcpy_to_fb(my_graph_mem + paga, (unsigned char *)&color, vga_bytes, 0);
paga += vga_linewidth;
}
vga_page = page;
END_MOUSE
return;
}else{
dest += remains * vga_linewidth;
n -= remains;
for (; remains; remains--) {
memcpy_to_fb(my_graph_mem + paga, (unsigned char *)&color, vga_bytes, 0);
paga += vga_linewidth;
}
vga_setpage(++page);
goto again;
}
}
/* Works for any pixel length */
static void draw_vline_paged(struct graphics_device *dev, int x, int y1, int y2, long color)
{
int lina,page,paga,remains,n;
/* lina: linear address withing the screen
* page: page number
* paga: 16-bit address within the page
* remains: how many bytes remain in the current page
* n: how many pixels remain to be drawn
*/
VLINE_CLIP_PREFACE;
SYNC
lina=y1*vga_linewidth+x*vga_bytes;
n=y2-y1;
page=lina>>16;
my_setpage(page);
again:
/* Invariant here: n>=1
* lina points to a begin of pixel
* page is set to page
*/
paga=lina&0xffff;
remains=65536-paga;
if (remains<vga_bytes){
memcpy_to_fb(my_graph_mem + paga, (unsigned char *)&color, remains, 0);
vga_setpage(++page);
memcpy_to_fb(my_graph_mem, (unsigned char *)&color + remains, vga_bytes - remains, 0);
lina+=vga_linewidth;
n--;
if (!n) goto end;
goto again;
}
remains=(remains-vga_bytes)/vga_linewidth+1;
if (remains>=n){
for (;n;n--){
memcpy_to_fb(my_graph_mem + paga, (unsigned char *)&color, vga_bytes, 0);
paga+=vga_linewidth;
}
end:
vga_page=page;
END_MOUSE
return;
}else{
lina+=remains*vga_linewidth;
n-=remains;
for (;remains;remains--){
memcpy_to_fb(my_graph_mem + paga, (unsigned char *)&color, vga_bytes, 0);
paga+=vga_linewidth;
}
if (paga>=65536)vga_setpage(++page);
goto again;
}
}
#define SCROLL_CLIP_PREFACE \
int mouse_hidden;\
TEST_INACTIVITY_0\
TEST_MOUSE(dev->clip.x1, dev->clip.x2, dev->clip.y1, dev->clip.y2)
/* When scx is <0, moves the data x1. Scrolls the whole clip window */
static int scroll_accel(struct graphics_device *dev, struct rect_set **ignore, int scx, int scy)
{
SCROLL_CLIP_PREFACE
vga_accel(ACCEL_SCREENCOPY,
dev->clip.x1 - (scx < 0 ? scx : 0),
dev->clip.y1 - (scy < 0 ? scy : 0),
dev->clip.x1 + (scx >= 0 ? scx : 0),
dev->clip.y1 + (scy >= 0 ? scy : 0),
dev->clip.x2 - dev->clip.x1 - abs(scx),
dev->clip.y2 - dev->clip.y1 - abs(scy));
END_MOUSE
return 1;
}
static int scroll_scansegment(struct graphics_device *dev, struct rect_set **ignore, int scx, int scy)
{
int y, len, x_src, x_dest;
SCROLL_CLIP_PREFACE
SYNC
len = dev->clip.x2 - dev->clip.x1 - abs(scx);
x_src = dev->clip.x1 - (scx < 0 ? scx : 0);
x_dest = dev->clip.x1 + (scx >= 0 ? scx : 0);
if (scy > 0) {
/* Down */
for (y = dev->clip.y2 - 1; y >= dev->clip.y1 + scy; y--) {
vga_getscansegment(scroll_buffer, x_src, y - scy, len);
vga_drawscansegment(scroll_buffer, x_dest, y, len);
}
} else {
/* Up */
for (y = dev->clip.y1 - scy; y < dev->clip.y2; y++) {
vga_getscansegment(scroll_buffer, x_src, y, len);
vga_drawscansegment(scroll_buffer, x_dest, y + scy, len);
}
}
END_MOUSE
return 1;
}
static int scroll_linear(struct graphics_device *dev, struct rect_set **ignore, int scx, int scy)
{
unsigned char *dest, *src;
int y, len, dest_off, src_off;
SCROLL_CLIP_PREFACE
SYNC
if (scx >= 0) {
len = (dev->clip.x2 - dev->clip.x1 - scx) * vga_bytes;
dest_off = scx * vga_bytes;
src_off = 0;
} else {
len = (dev->clip.x2 - dev->clip.x1 + scx) * vga_bytes;
dest_off = 0;
src_off = -scx * vga_bytes;
}
if (scy > 0) {
/* Down */
dest = my_graph_mem + (dev->clip.y2 - 1) * vga_linewidth + dev->clip.x1 * vga_bytes;
src = dest - vga_linewidth * scy;
dest += dest_off;
src += src_off;
for (y = dev->clip.y2 - dev->clip.y1 - scy; y; y--) {
memcpy_to_fb(dest, src, len, 1);
dest -= vga_linewidth;
src -= vga_linewidth;
}
} else {
/* Up */
dest = my_graph_mem + dev->clip.y1 * vga_linewidth + dev->clip.x1 * vga_bytes;
src = dest - vga_linewidth * scy;
dest += dest_off;
src += src_off;
for (y = dev->clip.y2 - dev->clip.y1 + scy; y; y--) {
if (scy)
memcpy_to_fb(dest, src, len, 1);
else
memmove_in_fb(dest, src, len);
dest += vga_linewidth;
src += vga_linewidth;
}
}
END_MOUSE
return 1;
}
static inline void get_row(unsigned char *bptr, int lina, int len)
{
int page=lina>>16;
int paga=lina&0xffff;
int remains;
my_setpage(page);
remains=65536-paga;
again:
if (remains>=len){
memcpy(bptr,my_graph_mem+paga,len);
vga_page=page;
return;
}else{
memcpy(bptr,my_graph_mem+paga,remains);
paga=0;
bptr+=remains;
len-=remains;
remains=65536;
vga_setpage(++page);
goto again;
}
}
static int scroll_paged(struct graphics_device *dev, struct rect_set **ignore, int scx, int scy)
{
int dest, src, y, len, dest_off, src_off;
SCROLL_CLIP_PREFACE
SYNC
if (scx >= 0) {
len = (dev->clip.x2 - dev->clip.x1 - scx) * vga_bytes;
dest_off = scx * vga_bytes;
src_off = 0;
} else {
len = (dev->clip.x2 - dev->clip.x1 + scx) * vga_bytes;
dest_off = 0;
src_off = -scx * vga_bytes;
}
if (scy > 0) {
/* Down */
dest = (dev->clip.y2 - 1) * vga_linewidth + dev->clip.x1 * vga_bytes;
src = dest - vga_linewidth * scy;
dest += dest_off;
src += src_off;
for (y = dev->clip.y2 - dev->clip.y1 - scy; y; y--) {
get_row(scroll_buffer, src, len);
paged_memcpy(dest, scroll_buffer, len);
dest -= vga_linewidth;
src -= vga_linewidth;
}
} else {
/* Up */
dest = dev->clip.y1 * vga_linewidth + dev->clip.x1 * vga_bytes;
src = dest - vga_linewidth * scy;
dest += dest_off;
src += src_off;
for (y = dev->clip.y2 - dev->clip.y1 + scy; y; y--) {
get_row(scroll_buffer, src, len);
paged_memcpy(dest, scroll_buffer, len);
dest += vga_linewidth;
src += vga_linewidth;
}
}
END_MOUSE
return 1;
}
/* For modes where video memory is not directly accessible through svgalib */
static inline void fill_area_drawscansegment(struct graphics_device *dev, int x1, int y1, int x2, int y2, long color)
{
int xs;
int col=*(unsigned char *)&color;
FILL_CLIP_PREFACE
SYNC
xs=x2-x1;
memset(scroll_buffer,col,xs);
for (;y1<y2;y1++){
vga_drawscansegment(scroll_buffer,x1,y1,xs);
}
END_MOUSE
}
/* Emulates horizontal line by calling fill_area */
static void draw_hline_fill_area(struct graphics_device *dev, int x1, int y, int x2, long color)
{
svga_driver.fill_area(dev,x1,y,x2,y+1,color);
}
/* Emulates vline by fill_area */
static void draw_vline_fill_area(struct graphics_device *dev, int x, int y1, int y2, long color)
{
svga_driver.fill_area(dev,x,y1,x+1,y2, color);
}
/* This does no clipping and is used only by the mouse code
* length is in bytes, not in pixels
*/
static int drawscansegment_linear(unsigned char *colors, int x, int y, int length)
{
unsigned char *ptr = my_graph_mem + vga_linewidth * y + vga_bytes * x;
memcpy_to_fb(ptr, colors, length, 0);
return 0;
}
/* This does no clipping and is used only by the mouse code
* length is in bytes, not in pixels
*/
static int getscansegment_linear(unsigned char *colors, int x, int y, int length)
{
unsigned char *ptr = my_graph_mem + vga_linewidth * y + vga_bytes*x;
memcpy_to_fb(colors, ptr, length, 1);
return 0;
}
/* This does no clipping and is used only by the mouse code
* length is in bytes, not in pixels
*/
static int drawscansegment_paged(unsigned char *colors, int x, int y, int length)
{
int lina = vga_linewidth * y + vga_bytes * x;
paged_memcpy(lina, colors, length);
return 0;
}
/* This does no clipping and is used only by the mouse code
* length is in the bytes, not in pixels
*/
static int getscansegment_paged(unsigned char *colors, int x, int y, int length)
{
int lina=vga_linewidth*y+vga_bytes*x;
get_row(colors, lina, length);
return 0;
}
static void alloc_scroll_buffer(void)
{
if (!scroll_buffer) {
if ((unsigned)xsize > (unsigned)MAXINT / fb_pixelsize) overalloc();
scroll_buffer=mem_alloc(xsize*fb_pixelsize);
}
}
static void setup_functions(void)
{
svga_driver.flags &= ~GD_DONT_USE_SCROLL;
if (accel_avail&ACCELFLAG_SETMODE){
do_sync=1;
vga_accel(ACCEL_SETMODE, BLITS_IN_BACKGROUND);
}else do_sync=0;
svga_driver.get_color = get_color_fn(svga_driver.depth);
if (!svga_driver.get_color) internal_error("Unknown bit depth %x", svga_driver.depth);
switch (vga_colors) {
case 2:
internal_error("2-color modes are not supported by links as they are buggy in svgalib and incapable of colors");
case 16:
alloc_scroll_buffer();
svga_driver.draw_bitmap = draw_bitmap_drawscansegment;
svga_driver.scroll = scroll_scansegment;
svga_driver.flags |= GD_DONT_USE_SCROLL;
svga_driver.fill_area = fill_area_drawscansegment;
svga_driver.draw_hline = draw_hline_fill_area;
svga_driver.draw_vline = draw_vline_fill_area;
mouse_getscansegment = vga_getscansegment;
mouse_drawscansegment = vga_drawscansegment;
break;
default:
mouse_getscansegment = vga_getscansegment;
mouse_drawscansegment = vga_drawscansegment;
if (accel_avail & ACCELFLAG_PUTIMAGE) {
svga_driver.draw_bitmap = draw_bitmap_accel;
} else if (vga_linear) {
svga_driver.draw_bitmap = draw_bitmap_linear;
} else if (mode_x) {
svga_driver.draw_bitmap = draw_bitmap_drawscansegment;
} else {
svga_driver.draw_bitmap = draw_bitmap_paged;
}
if (accel_avail & ACCELFLAG_FILLBOX) svga_driver.fill_area = fill_area_accel_box;
else if (accel_avail & ACCELFLAG_DRAWLINE) svga_driver.fill_area = fill_area_accel_lines;
else if (vga_linear) svga_driver.fill_area = fill_area_linear;
else if (mode_x) svga_driver.fill_area = fill_area_drawscansegment;
else svga_driver.fill_area = fill_area_paged;
if (accel_avail & ACCELFLAG_DRAWLINE) {
svga_driver.draw_hline = draw_hline_accel_line;
svga_driver.draw_vline = draw_vline_accel_line;
} else if (accel_avail & ACCELFLAG_FILLBOX) {
svga_driver.draw_hline = draw_hline_accel_box;
svga_driver.draw_vline = draw_vline_accel_box;
} else if (vga_linear) {
svga_driver.draw_hline = draw_hline_linear;
svga_driver.draw_vline = draw_vline_linear;
} else if (mode_x) {
svga_driver.draw_hline = draw_hline_fill_area;
svga_driver.draw_vline = draw_vline_fill_area;
} else {
/* Paged memory access */
svga_driver.draw_hline = draw_hline_paged;
switch (vga_bytes)
{
case 1:
svga_driver.draw_vline = draw_vline_paged_1;
break;
#ifdef t2c
case 2:
svga_driver.draw_vline = draw_vline_paged_2;
break;
#endif /* #ifdef t2c */
#ifdef t4c
case 4:
svga_driver.draw_vline = draw_vline_paged_4;
break;
#endif /* #ifdef t4c */
default:
if (vga_bytes & (vga_bytes - 1))
svga_driver.draw_vline = draw_vline_paged;
else
svga_driver.draw_vline = draw_vline_paged_aligned;
break;
}
}
if (vga_colors >= 256) {
if (vga_linear) {
mouse_drawscansegment = drawscansegment_linear;
mouse_getscansegment = getscansegment_linear;
} else if (!mode_x) {
mouse_drawscansegment = drawscansegment_paged;
mouse_getscansegment = getscansegment_paged;
}
}
if (accel_avail & ACCELFLAG_SCREENCOPY) {
svga_driver.scroll = scroll_accel;
} else if (vga_linear) {
svga_driver.scroll = scroll_linear;
svga_driver.flags |= GD_DONT_USE_SCROLL;
} else if (mode_x) {
alloc_scroll_buffer();
svga_driver.scroll = scroll_scansegment;
svga_driver.flags |= GD_DONT_USE_SCROLL;
} else {
alloc_scroll_buffer();
svga_driver.scroll = scroll_paged;
svga_driver.flags |= GD_DONT_USE_SCROLL;
}
}
}
#if 0
void dump_mode_info_into_file(vga_modeinfo* i)
{
FILE *f;
f=fopen(".links_svga_modeinfo","w");
if (!f) return;
fprintf(f,"Resolution %d*%d\n",i->width,i->height);
fprintf(f,"%d bytes per screen pixel\n",i->bytesperpixel);
fprintf(f,"%d colors\n",i->colors);
fprintf(f,"Linewidth %d bytes\n",i->linewidth);
fprintf(f,"Maximum logical width %d bytes\n",i->maxlogicalwidth);
fprintf(f,"Start address rangemask 0x%x\n",i->startaddressrange);
fprintf(f,"Max. pixels per logical screen %d\n",i->maxpixels);
fprintf(f,"bitblt %s\n",i->haveblit&HAVE_BITBLIT?"yes":"no");
fprintf(f,"fillblt %s\n",i->haveblit&HAVE_FILLBLIT?"yes":"no");
fprintf(f,"imageblt %s\n",i->haveblit&HAVE_IMAGEBLIT?"yes":"no");
fprintf(f,"hlinelistblt %s\n",i->haveblit&HAVE_HLINELISTBLIT?"yes":"no");
fprintf(f,"read/write page %s\n",i->flags&HAVE_RWPAGE?"yes":"no");
fprintf(f,"Interlaced %s\n",i->flags&IS_INTERLACED?"yes":"no");
fprintf(f,"Mode X layout %s\n",i->flags&IS_MODEX?"yes":"no");
fprintf(f,"Dynamically loaded %s\n",i->flags&IS_DYNAMICMODE?"yes":"no");
fprintf(f,"Linear: %s\n",vga_linear?"yes":"no");
fprintf(f,"Misordered %s\n",i->flags&RGB_MISORDERED?"yes":"no");
if (!i->flags&EXT_INFO_AVAILABLE){
fprintf(f,"Old svgalib, extended info is not available\n");
}else{
fprintf(f,"Chiptype 0x%x\n",i->chiptype);
fprintf(f,"Memory %dKB\n",i->memory);
fprintf(f,"Linewidth Unit %d\n",i->linewidth_unit);
fprintf(f,"Aperture size %d\n",i->aperture_size);
}
fprintf(f,"Accelerated putimage: %s\n",svga_driver.draw_bitmap==draw_bitmap_accel?"yes":"no");
fclose(f);
}
#endif
static void svgalib_key_in(struct itrm *p, unsigned char *ev_, int size)
{
struct links_event *ev = (struct links_event *)(void *)ev_;
if (size != sizeof(struct links_event)) return;
if (ev->ev == EV_ABORT) terminate_loop = 1;
if (ev->ev != EV_KBD) return;
if (ev->y & KBD_PASTING) goto skip;
if ((ev->y & (KBD_CTRL | KBD_ALT)) == KBD_ALT && ev->x >= '0' && ev->x <= '9') {
switch_virtual_device((ev->x - '1' + 10) % 10);
return;
}
skip:
if (g_kbd_codepage(&svga_driver) != utf8_table && ev->x >= 128 && ev->x <= 255)
if ((ev->x = cp2u(ev->x, g_kbd_codepage(&svga_driver))) == -1) return;
if (current_virtual_device && current_virtual_device->keyboard_handler) current_virtual_device->keyboard_handler(current_virtual_device, ev->x, ev->y);
}
#ifndef MOUSE_FOURTHBUTTON
#define MOUSE_FOURTHBUTTON 0
#endif
#ifndef MOUSE_FIFTHBUTTON
#define MOUSE_FIFTHBUTTON 0
#endif
#ifndef MOUSE_SIXTHBUTTON
#define MOUSE_SIXTHBUTTON 0
#endif
#define BUTTON_MASK (MOUSE_RIGHTBUTTON | MOUSE_MIDDLEBUTTON | MOUSE_LEFTBUTTON | MOUSE_FOURTHBUTTON | MOUSE_FIFTHBUTTON /*| MOUSE_SIXTHBUTTON*/)
static inline void mouse_aggregate_flush(void)
{
if (!mouse_aggregate_flag) return;
mouse_aggregate_flag=0;
if (current_virtual_device && current_virtual_device->mouse_handler) current_virtual_device->mouse_handler(current_virtual_device, mouse_x, mouse_y, mouse_aggregate_action);
}
/* Only calls appropriate callbacks, doesn't draw anything. */
#ifdef HAVE_MOUSE_GETPOSITION_6D
static void mouse_event_handler(int button, int dx, int dy, int dz, int drx, int dry, int drz)
{
#else
static void mouse_event_handler(int button, int dx, int dy)
{
int drx = 0, dry = 0;
#endif
int moved, old_mouse_x, old_mouse_y;
void (*mh)(struct graphics_device *, int, int, int);
struct graphics_device *cd = current_virtual_device;
mh = cd ? cd->mouse_handler : (void(*)(struct graphics_device *dev, int x, int y, int buttons))NULL;
old_mouse_x = mouse_x;
old_mouse_y = mouse_y;
mouse_x += dx;
if (mouse_x >= xsize) mouse_x = xsize - 1;
else if (mouse_x < 0) mouse_x = 0;
mouse_y += dy;
if (mouse_y >= ysize) mouse_y = ysize - 1;
else if (mouse_y < 0) mouse_y = 0;
redraw_mouse();
moved = (old_mouse_x != mouse_x || old_mouse_y != mouse_y);
/* Test movement without buttons */
if (!(mouse_buttons & BUTTON_MASK) && moved) {
mouse_aggregate_flag=1;
mouse_aggregate_action=B_MOVE;
}
/* Test presses */
if ((button&MOUSE_LEFTBUTTON)&&!(mouse_buttons&MOUSE_LEFTBUTTON)){
mouse_aggregate_flush();
if (mh) mh(cd,mouse_x, mouse_y,B_LEFT|B_DOWN);
}
if ((button&MOUSE_MIDDLEBUTTON)&&!(mouse_buttons&MOUSE_MIDDLEBUTTON)){
mouse_aggregate_flush();
if (mh) mh(cd,mouse_x, mouse_y,B_MIDDLE|B_DOWN);
}
if ((button&MOUSE_RIGHTBUTTON)&&!(mouse_buttons&MOUSE_RIGHTBUTTON)){
mouse_aggregate_flush();
if (mh) mh(cd,mouse_x, mouse_y,B_RIGHT|B_DOWN);
}
if ((button&MOUSE_FOURTHBUTTON)&&!(mouse_buttons&MOUSE_FOURTHBUTTON)){
mouse_aggregate_flush();
if (mh) mh(cd,mouse_x, mouse_y,B_FOURTH|B_DOWN);
}
if ((button&MOUSE_FIFTHBUTTON)&&!(mouse_buttons&MOUSE_FIFTHBUTTON)){
mouse_aggregate_flush();
if (mh) mh(cd,mouse_x, mouse_y,B_FIFTH|B_DOWN);
}
if ((button&MOUSE_SIXTHBUTTON)&&!(mouse_buttons&MOUSE_SIXTHBUTTON)){
mouse_aggregate_flush();
/*if (mh) mh(cd,mouse_x, mouse_y,B_SIXTH|B_DOWN);*/
switch_virtual_device(VD_NEXT);
}
/* Test releases */
if (!(button&MOUSE_LEFTBUTTON)&&(mouse_buttons&MOUSE_LEFTBUTTON)){
mouse_aggregate_flush();
if (mh) mh(cd,mouse_x, mouse_y,B_LEFT|B_UP);
}
if (!(button&MOUSE_MIDDLEBUTTON)&&(mouse_buttons&MOUSE_MIDDLEBUTTON)){
mouse_aggregate_flush();
if (mh) mh(cd,mouse_x, mouse_y,B_MIDDLE|B_UP);
}
if (!(button&MOUSE_RIGHTBUTTON)&&(mouse_buttons&MOUSE_RIGHTBUTTON)){
mouse_aggregate_flush();
if (mh) mh(cd,mouse_x, mouse_y,B_RIGHT|B_UP);
}
if (!(button&MOUSE_FOURTHBUTTON)&&(mouse_buttons&MOUSE_FOURTHBUTTON)){
mouse_aggregate_flush();
if (mh) mh(cd,mouse_x, mouse_y,B_FOURTH|B_UP);
}
if (!(button&MOUSE_FIFTHBUTTON)&&(mouse_buttons&MOUSE_FIFTHBUTTON)){
mouse_aggregate_flush();
if (mh) mh(cd,mouse_x, mouse_y,B_FIFTH|B_UP);
}
if (!(button&MOUSE_SIXTHBUTTON)&&(mouse_buttons&MOUSE_SIXTHBUTTON)){
mouse_aggregate_flush();
/*if (mh) mh(cd,mouse_x, mouse_y,B_SIXTH|B_UP);*/
}
if (drx < 0 && mh) mh(cd, mouse_x, mouse_y, B_MOVE | B_WHEELUP);
if (drx > 0 && mh) mh(cd, mouse_x, mouse_y, B_MOVE | B_WHEELDOWN);
if (dry < 0 && mh) mh(cd, mouse_x, mouse_y, B_MOVE | B_WHEELLEFT);
if (dry > 0 && mh) mh(cd, mouse_x, mouse_y, B_MOVE | B_WHEELRIGHT);
/* Test drag */
if (! ((button^mouse_buttons) & BUTTON_MASK ) && moved && (button &
BUTTON_MASK)){
mouse_aggregate_flag=1;
mouse_aggregate_action=(
button&MOUSE_LEFTBUTTON?B_LEFT:
button&MOUSE_RIGHTBUTTON?B_RIGHT:
button&MOUSE_MIDDLEBUTTON?B_MIDDLE:
button&MOUSE_FOURTHBUTTON?B_FOURTH:
button&MOUSE_FIFTHBUTTON?B_FIFTH:
/*button&MOUSE_SIXTHBUTTON?B_SIXTH:*/
0) | B_DRAG;
}
mouse_buttons=button;
}
#undef BUTTON_MASK
/* Flushes the background_buffer onscreen where it was originally taken from. */
static void place_mouse_background(void)
{
struct bitmap bmp;
struct graphics_device *current_virtual_device_backup;
bmp.x = arrow_width;
bmp.y = arrow_height;
bmp.skip = arrow_width * fb_pixelsize;
bmp.data = background_buffer;
current_virtual_device_backup = current_virtual_device;
current_virtual_device = mouse_graphics_device;
svga_driver.draw_bitmap(mouse_graphics_device, &bmp, background_x, background_y);
current_virtual_device = current_virtual_device_backup;
}
/* Only when the old and new mouse don't interfere. Using it on interfering mouses would
* cause a flicker.
*/
static void hide_mouse(void)
{
global_mouse_hidden = 1;
place_mouse_background();
}
/* Gets background from the screen (clipping provided only right and bottom) to the
* passed buffer.
*/
static void get_mouse_background(unsigned char *buffer_ptr)
{
int width,height,skip,x,y;
skip=arrow_width*fb_pixelsize;
x=mouse_x;
y=mouse_y;
width=fb_pixelsize*(arrow_width+x>xsize?xsize-x:arrow_width);
height=arrow_height+y>ysize?ysize-y:arrow_height;
SYNC
for (;height;height--){
mouse_getscansegment(buffer_ptr,x,y,width);
buffer_ptr+=skip;
y++;
}
}
/* Overlays the arrow's image over the mouse_buffer
* Doesn't draw anything into the screen
*/
static void render_mouse_arrow(void)
{
int x,y, reg0, reg1;
unsigned char *mouse_ptr=mouse_buffer;
const unsigned *arrow_ptr=arrow;
for (y=arrow_height;y;y--){
reg0=*arrow_ptr;
reg1=arrow_ptr[1];
arrow_ptr+=2;
for (x=arrow_width;x;)
{
int mask=1<<(--x);
if (reg0&mask)
memcpy (mouse_ptr, &mouse_black, fb_pixelsize);
else if (reg1&mask)
memcpy (mouse_ptr, &mouse_white, fb_pixelsize);
mouse_ptr+=fb_pixelsize;
}
}
}
static void place_mouse(void)
{
struct bitmap bmp;
struct graphics_device *current_graphics_device_backup;
bmp.x = arrow_width;
bmp.y = arrow_height;
bmp.skip = arrow_width * fb_pixelsize;
bmp.data = mouse_buffer;
current_graphics_device_backup = current_virtual_device;
current_virtual_device = mouse_graphics_device;
/* We do need to worry about SYNC because draw_bitmap already
* does it (if necessary)
*/
svga_driver.draw_bitmap(mouse_graphics_device, &bmp, mouse_x, mouse_y);
current_virtual_device = current_graphics_device_backup;
global_mouse_hidden=0;
}
/* Only when the old and the new mouse positions do not interfere. Using this routine
* on interfering positions would cause a flicker.
*/
static void show_mouse(void)
{
get_mouse_background(background_buffer);
background_x=mouse_x;
background_y=mouse_y;
memcpy(mouse_buffer,background_buffer,fb_pixelsize*arrow_area);
render_mouse_arrow();
place_mouse();
}
/* Doesn't draw anything into the screen
*/
static void put_and_clip_background_buffer_over_mouse_buffer(void)
{
unsigned char *bbufptr=background_buffer, *mbufptr=mouse_buffer;
int left=background_x-mouse_x;
int top=background_y-mouse_y;
int right,bottom;
int bmpixelsizeL=fb_pixelsize;
int number_of_bytes;
int byte_skip;
right=left+arrow_width;
bottom=top+arrow_height;
if (left<0){
bbufptr-=left*bmpixelsizeL;
left=0;
}
if (right>arrow_width) right=arrow_width;
if (top<0){
bbufptr-=top*bmpixelsizeL*arrow_width;
top=0;
}
if (bottom>arrow_height) bottom=arrow_height;
mbufptr+=bmpixelsizeL*(left+arrow_width*top);
byte_skip=arrow_width*bmpixelsizeL;
number_of_bytes=bmpixelsizeL*(right-left);
for (;top<bottom;top++){
memcpy(mbufptr,bbufptr,number_of_bytes);
mbufptr+=byte_skip;
bbufptr+=byte_skip;
}
}
/* This draws both the contents of background_buffer and mouse_buffer in a scan
* way (left-right, top-bottom), so the flicker is reduced.
*/
static inline void place_mouse_composite(void)
{
int mouse_left=mouse_x;
int mouse_top=mouse_y;
int background_left=background_x;
int background_top=background_y;
int mouse_right=mouse_left+arrow_width;
int mouse_bottom=mouse_top+arrow_height;
int background_right=background_left+arrow_width;
int background_bottom=background_top+arrow_height;
int skip=arrow_width*fb_pixelsize;
int background_length,mouse_length;
unsigned char *mouse_ptr=mouse_buffer,*background_ptr=background_buffer;
int yend;
/* First let's sync to the beam - wait for the beginning of vertical retrace
* (it would be better to wait for the beginning of the blank, however,
* svgalib doesn't provide it as VGA and SVGA cards don't provide it
*/
/* This will probably not make any good anyway.
if (vga_colors >= 256)
vga_waitretrace();
*/
if (mouse_bottom>ysize) mouse_bottom=ysize;
if (background_bottom>ysize) background_bottom=ysize;
SYNC
/* We have to sync because mouse_drawscansegment does not wait for
* the accelerator to finish. But we never waste time here because
* mouse_drawscansegment is never accelerated.
*/
/* Let's do the top part */
if (background_top<mouse_top){
/* Draw the background */
background_length=background_right>xsize?xsize-background_left
:arrow_width;
for (;background_top<mouse_top;background_top++){
mouse_drawscansegment(background_ptr,background_left
,background_top,background_length*fb_pixelsize);
background_ptr+=skip;
}
}else if (background_top>mouse_top){
/* Draw the mouse */
mouse_length=mouse_right>xsize
?xsize-mouse_left:arrow_width;
for (;mouse_top<background_top;mouse_top++){
mouse_drawscansegment(mouse_ptr,mouse_left,mouse_top,mouse_length*fb_pixelsize);
mouse_ptr+=skip;
}
}
/* Let's do the middle part */
yend=mouse_bottom<background_bottom?mouse_bottom:background_bottom;
if (background_left<mouse_left){
/* Draw background, mouse */
mouse_length=mouse_right>xsize?xsize-mouse_left:arrow_width;
for (;mouse_top<yend;mouse_top++){
mouse_drawscansegment(background_ptr,background_left,mouse_top
,(mouse_left-background_left)*fb_pixelsize);
mouse_drawscansegment(mouse_ptr,mouse_left,mouse_top,mouse_length*fb_pixelsize);
mouse_ptr+=skip;
background_ptr+=skip;
}
}else{
int l1, l2, l3;
/* Draw mouse, background */
mouse_length=mouse_right>xsize?xsize-mouse_left:arrow_width;
background_length=background_right-mouse_right;
if (background_length+mouse_right>xsize)
background_length=xsize-mouse_right;
l1=mouse_length*fb_pixelsize;
l2=(mouse_right-background_left)*fb_pixelsize;
l3=background_length*fb_pixelsize;
for (;mouse_top<yend;mouse_top++){
mouse_drawscansegment(mouse_ptr,mouse_left,mouse_top,l1);
if (background_length>0)
mouse_drawscansegment(
background_ptr + l2,
mouse_right,mouse_top, l3);
mouse_ptr+=skip;
background_ptr+=skip;
}
}
if (background_bottom<mouse_bottom){
/* Count over bottoms! tops will be invalid! */
/* Draw mouse */
mouse_length=mouse_right>xsize?xsize-mouse_left
:arrow_width;
for (;background_bottom<mouse_bottom;background_bottom++){
mouse_drawscansegment(mouse_ptr,mouse_left,background_bottom
,mouse_length*fb_pixelsize);
mouse_ptr+=skip;
}
}else{
/* Draw background */
background_length=background_right>xsize?xsize-background_left
:arrow_width;
for (;mouse_bottom<background_bottom;mouse_bottom++){
mouse_drawscansegment(background_ptr,background_left,mouse_bottom
,background_length*fb_pixelsize);
background_ptr+=skip;
}
}
}
/* This moves the mouse a sophisticated way when the old and new position of the
* cursor overlap.
*/
static inline void redraw_mouse_sophisticated(void)
{
int new_background_x, new_background_y;
get_mouse_background(mouse_buffer);
put_and_clip_background_buffer_over_mouse_buffer();
memcpy(new_background_buffer,mouse_buffer,fb_pixelsize*arrow_area);
new_background_x=mouse_x;
new_background_y=mouse_y;
render_mouse_arrow();
place_mouse_composite();
memcpy(background_buffer,new_background_buffer,fb_pixelsize*arrow_area);
background_x=new_background_x;
background_y=new_background_y;
}
static void redraw_mouse(void)
{
if (flags) return; /* We are not drawing */
if (mouse_x!=background_x||mouse_y!=background_y){
if (RECTANGLES_INTERSECT(
background_x, background_x+arrow_width,
mouse_x, mouse_x+arrow_width,
background_y, background_y+arrow_height,
mouse_y, mouse_y+arrow_height)){
redraw_mouse_sophisticated();
}else{
/* Do a normal hide/show */
get_mouse_background(mouse_buffer);
memcpy(new_background_buffer,
mouse_buffer,arrow_area*fb_pixelsize);
render_mouse_arrow();
hide_mouse();
place_mouse();
memcpy(background_buffer,new_background_buffer
,arrow_area*fb_pixelsize);
background_x=mouse_x;
background_y=mouse_y;
}
}
}
static unsigned char *svga_get_driver_param(void)
{
return svga_driver_param;
}
static void generate_palette_outer(void)
{
if (vga_colors == 16 || vga_colors == 256) {
struct irgb *palette;
palette = mem_alloc(vga_colors * sizeof(*palette));
generate_palette(palette);
set_palette(palette);
mem_free(palette);
/* Palette in SVGAlib will be always color cube */
}
}
static void vga_update_palette(void)
{
if (!svga_driver.param->palette_mode)
svga_driver.depth |= 0x300;
else
svga_driver.depth &= ~0x300;
svga_driver.get_color = get_color_fn(svga_driver.depth);
if (!svga_driver.get_color) internal_error("Unknown bit depth %x", svga_driver.depth);
mouse_black = svga_driver.get_color(0);
mouse_white = svga_driver.get_color(0xffffff);
generate_palette_outer();
}
/* This is to be called after vga_setmode and sets up accelerator,
* svgalib functions */
static void setup_mode(int mode)
{
vga_modeinfo *i;
int sig;
accel_avail=vga_ext_set(VGA_EXT_AVAILABLE,VGA_AVAIL_ACCEL);
if (vga_ext_set(VGA_EXT_AVAILABLE, VGA_AVAIL_SET)&VGA_CLUT8){
vga_ext_set(VGA_EXT_SET,VGA_CLUT8);
palette_depth=8;
}else palette_depth=6;
i=vga_getmodeinfo(mode);
vga_bytes=i->bytesperpixel;
fb_pixelsize=vga_bytes?vga_bytes:1;
vga_misordered=!!(i->flags&RGB_MISORDERED);
mode_x=!!(i->flags&IS_MODEX);
vga_linear=!!(i->flags&IS_LINEAR);
/*
if (!vga_linear && i->flags&CAPABLE_LINEAR && 0<=vga_setlinearaddressing()) vga_linear=1;
*/
my_graph_mem = vga_getgraphmem();
svga_driver.x = xsize = i->width;
svga_driver.y = ysize = i->height;
vga_colors = i->colors;
if (xsize == 320 && ysize == 200 && i->colors == 256) vga_linear = 1; /* The mode
does not need to page :-) */
vga_linewidth = i->linewidth;
if (!vga_linear) {
vga_page=-1;
}
vga_misordered = !!(i->flags & RGB_MISORDERED);
svga_driver.flags &= ~GD_SELECT_PALETTE;
/*dump_mode_info_into_file(i);*/
svga_driver.depth = 0;
svga_driver.depth |= vga_misordered << 8;
switch (vga_colors) {
case 16:
sig = 4;
break;
case 256:
sig = 8;
if (!svga_driver.param->palette_mode)
svga_driver.depth |= 0x300;
svga_driver.flags |= GD_SELECT_PALETTE;
break;
case 32768:
sig = 15;
break;
case 65536:
sig = 16;
break;
case 16777216:
sig = 24;
break;
default:
sig = 0; /* Only to suppress warning */
break;
}
svga_driver.depth |= sig << 3;
svga_driver.depth |= fb_pixelsize;
/* setup_functions uses depth. */
setup_functions();
generate_palette_outer();
}
#ifndef __SPAD__
static void vtswitch_handler(void *nothing)
{
int oktowrite;
vga_unlockvc();
vga_lockvc();
oktowrite = vga_oktowrite();
if (flags == 1 && oktowrite) {
flags = 0;
setup_mode(vga_mode);
if (mouse_works) {
mouse_seteventhandler((void *)mouse_event_handler);
}
if (current_virtual_device) current_virtual_device->redraw_handler(current_virtual_device, &current_virtual_device->size);
}
flags = (flags & ~1) | !oktowrite;
svgalib_timer_id = install_timer(100, vtswitch_handler, NULL);
}
#endif
static void svga_ctrl_c(void *i_)
{
kbd_ctrl_c();
}
/* Param: one string which is to be compared with one from modes.
* Copies the svga_driver into gr_driver.
* Returns: 0 OK
* 1 Passed mode unknown by svga_driver
* 2 Passed mode unknown by svgalib
* mikulas: Change: Returns: NULL: OK
* non-null: poiner to string with error
* description, string must be freed
*/
static unsigned char *svga_init_driver(unsigned char *param, unsigned char *display)
{
int j;
kbd_set_raw = 0;
vga_init();
svga_driver.flags |= GD_NEED_CODEPAGE;
j = 0;
svga_driver_param = NULL;
if (!param || !*param) goto not_found;
svga_driver_param=stracpy(param);
for (j = 0; (size_t)j < array_elements(modes); j++) {
if (!casestrcmp(cast_uchar modes[j].name, param)) {
goto found;
}
}
j = 1;
not_found:
{
unsigned char *m = init_str();
int l = 0;
int f = 0;
if (j) {
add_to_str(&m, &l, cast_uchar "Video mode ");
add_to_str(&m, &l, param);
add_to_str(&m, &l,
j == 1 ? cast_uchar " not supported by svgalib" :
j == 2 ? cast_uchar " not supported by your video card" :
cast_uchar " could not be set");
add_to_str(&m, &l, cast_uchar ".\n");
} else add_to_str(&m, &l, cast_uchar "There is no default video mode.\n");
for (j=0;(size_t)j<sizeof(modes)/sizeof(*modes);j++) if (vga_hasmode(modes[j].number)) {
if (f) add_to_str(&m, &l, cast_uchar ", ");
else f = 1, add_to_str(&m, &l, cast_uchar "The following modes are supported:\n");
add_to_str(&m, &l, cast_uchar modes[j].name);
}
if (f) add_to_str(&m, &l, cast_uchar "\nUse -mode switch to set video mode.\n");
else add_to_str(&m, &l, cast_uchar "There are no supported video modes. Links can't run on svgalib.\n");
if(svga_driver_param)mem_free(svga_driver_param),svga_driver_param=NULL;
return m;
}
found:
if (!vga_hasmode(modes[j].number)) {
j = 2;
goto not_found;
}
init_virtual_devices(&svga_driver, NUMBER_OF_DEVICES);
#ifdef MOUSE_NONE
if ((vga_getmousetype() & MOUSE_TYPE_MASK) == MOUSE_NONE) {
vga_setmousesupport(0);
mouse_works = 0;
} else
#endif
{
vga_setmousesupport(1);
mouse_works = 1;
}
vga_lockvc();
#ifndef __SPAD__
svgalib_timer_id = install_timer(100, vtswitch_handler, NULL);
#ifdef HAVE_VGA_RUNINBACKGROUND_VERSION
if (vga_runinbackground_version() >= 1)
#endif
vga_runinbackground(1);
#endif
vga_setmode_retry:
if (vga_setmode(modes[j].number) < 0) {
if (out_of_memory(0, NULL, 0))
goto vga_setmode_retry;
#ifndef __SPAD__
kill_timer(svgalib_timer_id);
#endif
vga_unlockvc();
shutdown_virtual_devices();
j = 3;
goto not_found;
}
vga_mode=modes[j].number;
setup_mode(modes[j].number);
svgalib_kbd = handle_svgalib_keyboard(svgalib_key_in);
if (mouse_works){
if ((unsigned)arrow_area > (unsigned)MAXINT / fb_pixelsize) overalloc();
mouse_buffer=mem_alloc(fb_pixelsize*arrow_area);
background_buffer=mem_alloc(fb_pixelsize*arrow_area);
new_background_buffer=mem_alloc(fb_pixelsize*arrow_area);
mouse_black=svga_driver.get_color(0);
mouse_white=svga_driver.get_color(0xffffff);
mouse_graphics_device=svga_driver.init_device();
virtual_devices[0] = NULL;
global_mouse_hidden=1;
background_x=mouse_x=xsize>>1;
background_y=mouse_y=ysize>>1;
show_mouse();
mouse_seteventhandler((void *)mouse_event_handler);
}else{
global_mouse_hidden=1;
/* To ensure hide_mouse and show_mouse will do nothing */
}
ignore_signals();
errno = 0;
while (signal(SIGTSTP, SIG_IGN) == SIG_ERR && errno == EINTR) errno = 0;
install_signal_handler(SIGINT, svga_ctrl_c, svgalib_kbd, 0);
return NULL;
}
/* Return value: 0 alloced on heap
* 1 alloced in vidram
* 2 alloced in X server shm
*/
static int svga_get_empty_bitmap(struct bitmap *dest)
{
if (dest->x && (unsigned)dest->x * (unsigned)dest->y / (unsigned)dest->x != (unsigned)dest->y) overalloc();
if ((unsigned)dest->x * (unsigned)dest->y > (unsigned)MAXINT / fb_pixelsize) overalloc();
dest->data=mem_alloc(dest->x*dest->y*fb_pixelsize);
dest->skip=dest->x*fb_pixelsize;
dest->flags=0;
return 0;
}
static int vga_block(struct graphics_device *dev)
{
int overridden;
overridden = (flags >> 1) & 1;
if (!overridden) {
svgalib_block_itrm(svgalib_kbd);
if (mouse_works) {
hide_mouse();
/* mouse_close(); This is not necessary as it is
handled by vga_setmode(TEXT). */
}
vga_setmode_retry:
if (vga_setmode(TEXT) < 0) {
if (out_of_memory(0, NULL, 0))
goto vga_setmode_retry;
fatal_exit("ERROR: vga_setmode failed");
}
}
flags |= 2;
return overridden;
}
static int vga_unblock(struct graphics_device *dev)
{
#ifdef DEBUG
if (!(flags & 2)) {
internal_error("vga_unblock called without vga_block");
return 0;
}
#endif /* #ifdef DEBUG */
flags &= ~2;
vga_setmousesupport(1);
vga_setmode_retry:
if (vga_setmode(vga_mode) < 0) {
if (out_of_memory(0, NULL, 0))
goto vga_setmode_retry;
fatal_exit("ERROR: vga_setmode failed");
}
setup_mode(vga_mode);
if (mouse_works) {
show_mouse();
mouse_seteventhandler((void *)mouse_event_handler);
}
svgalib_unblock_itrm(svgalib_kbd);
if (current_virtual_device) current_virtual_device->redraw_handler(current_virtual_device, &current_virtual_device->size);
return 0;
}
static void *svga_prepare_strip(struct bitmap *bmp, int top, int lines)
{
return (unsigned char *)bmp->data + bmp->skip * top;
}
static void svga_commit_strip(struct bitmap *bmp, int top, int lines)
{
return;
}
int vga_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
{
int retval,i;
if (drv != &svga_driver) return select(n, readfds, writefds, exceptfds, timeout);
/* The second flag here is to suppress mouse wait
* in blocked state */
retval = vga_waitevent((mouse_works && !(flags & 2) ? VGA_MOUSEEVENT : 0)
#ifdef VGA_REDRAWEVENT
| VGA_REDRAWEVENT
#endif
, readfds, writefds, exceptfds, timeout);
if (retval < 0) return retval;
#ifdef VGA_REDRAWEVENT
if (retval & VGA_REDRAWEVENT) {
if (current_virtual_device) current_virtual_device->redraw_handler(current_virtual_device, &current_virtual_device->size);
check_bottom_halves();
}
#endif
if (retval & VGA_MOUSEEVENT){
mouse_aggregate_flush();
/*redraw_mouse(); mikulas: dal jsem to do mouse_event_handler,
aby ukazatel mysi nezustaval pozadu za scrollbarem */
check_bottom_halves();
}
retval = 0;
for (i = 0; i < n; i++){
if (readfds && FD_ISSET(i, readfds)) retval++;
if (writefds && FD_ISSET(i, writefds)) retval++;
if (exceptfds && FD_ISSET(i, exceptfds)) retval++;
}
return retval;
}
struct graphics_driver svga_driver = {
cast_uchar "svgalib",
svga_init_driver,
init_virtual_device,
shutdown_virtual_device,
svga_shutdown_driver,
NULL,
NULL,
svga_get_driver_param,
NULL,
NULL,
NULL,
svga_get_empty_bitmap,
svga_register_bitmap,
svga_prepare_strip,
svga_commit_strip,
svga_unregister_bitmap,
NULL, /* svga_draw_bitmap */
NULL, /* get_color */
NULL, /* fill_area */
NULL, /* draw_hline */
NULL, /* draw_vline */
NULL, /* scroll */
NULL, /* set_clip_area */
NULL, /* flush */
vga_block, /* block */
vga_unblock, /* unblock */
vga_update_palette, /* set_palette */
NULL, /* get_real_colors */
NULL, /* set_title */
NULL, /* exec */
NULL, /* set_clipboard_text */
NULL, /* get_clipboard_text */
0, /* depth */
0, 0, /* size */
GD_NO_LIBEVENT
#ifndef SPAD
| GD_NOAUTO
#endif
, /* flags */
NULL, /* param */
};
#endif /* GRDRV_SVGALIB */