/* 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 #include #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>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=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=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 (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= 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_topxsize?xsize-background_left :arrow_width; for (;background_topmouse_top){ /* Draw the mouse */ mouse_length=mouse_right>xsize ?xsize-mouse_left:arrow_width; for (;mouse_topxsize?xsize-mouse_left:arrow_width; for (;mouse_topxsize?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_top0) mouse_drawscansegment( background_ptr + l2, mouse_right,mouse_top, l3); mouse_ptr+=skip; background_ptr+=skip; } } if (background_bottomxsize?xsize-mouse_left :arrow_width; for (;background_bottomxsize?xsize-background_left :arrow_width; for (;mouse_bottompalette_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, ¤t_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= 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, ¤t_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, ¤t_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 */