/* 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" /* :%s/->left/->clip.x1/g :%s/->right/->clip.x2/g :%s/->top/->clip.y1/g :%s/->bottom/->clip.y2/g */ #ifdef GRDRV_SVGALIB #include "links.h" #include "bits.h" #include #include #include "arrow.inc" 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 int mouse_works = 0; static unsigned char *svga_driver_param; /* NULL by default */ static int vga_mode; /* The mode that has been selected */ static struct graphics_device *backup_virtual_device; 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 int 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{ unsigned char *name; int number; }; /*-------------- GLOBAL VARIABLES --------------------------------------------*/ #define NUMBER_OF_DEVICES 10 #define TEST_INACTIVITY if (dev!=current_virtual_device) return; #define TEST_INACTIVITY_0 if (dev!=current_virtual_device) 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 }; /*--------------------------- 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; if (vga_colors==16){ if (palette_depth==6){ for (a=0;a<16;a++,palette++) { palette->r=(a&8)?63:0; palette->g=((a>>1)&3)*21; palette->b=(a&1)?63:0; } }else{ /* palette_depth==8 */ for (a=0;a<16;a++,palette++) { palette->r=(a&8)?255:0; palette->g=((a>>1)&3)*85; palette->b=(a&1)?255:0; } } }else{ /* vga_colors==256 */ if (palette_depth==6){ for (a=0;a<256;a++,palette++){ palette->r=((a>>5)&7)*9; palette->g=((a>>2)&7)*9; palette->b=(a&3)*21; } }else{ /* palette_depth==8 */ for (a=0;a<256;a++,palette++){ palette->r=((a>>5)&7)*36; palette->g=((a>>2)&7)*36; palette->b=(a&3)*84; } } } } static void set_palette(struct irgb *palette) { int r,g,b,c; for (c=0;cdata); } #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=hndl->x,ys=hndl->y;\ unsigned char *data=hndl->data;\ int mouse_hidden;\ \ TEST_INACTIVITY\ if (x>=dev->clip.x2||x+xs<=dev->clip.x1) return;\ if (y>=dev->clip.y2||y+ys<=dev->clip.y1) return;\ 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+=hndl->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* hndl, int x, int y) { CLIP_PREFACE if (xs*fb_pixelsize==hndl->skip) vga_accel(ACCEL_PUTIMAGE,x,y,xs,ys,data); else for(;ys;ys--){ vga_accel(ACCEL_PUTIMAGE,x,y,xs,1,data); data+=hndl->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(my_graph_mem+paga,src,len); vga_page=page; return; }else{ memcpy(my_graph_mem+paga,src,remains); 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* hndl, int x, int y) { int ys0; CLIP_PREFACE SYNC for (ys0=ys;ys0;ys0--){ vga_drawscansegment(data,x,y,xs); y++; data+=hndl->skip; } END_MOUSE } static inline void draw_bitmap_paged(struct graphics_device *dev, struct bitmap* hndl, int x, int y) { int scr_start; CLIP_PREFACE scr_start=y*vga_linewidth+x*vga_bytes; SYNC for(;ys;ys--){ paged_memcpy(scr_start,data,xs*vga_bytes); data+=hndl->skip; scr_start+=vga_linewidth; } END_MOUSE } static inline void draw_bitmap_linear(struct graphics_device *dev,struct bitmap* hndl, int x, int y) { unsigned char *scr_start; CLIP_PREFACE SYNC scr_start=my_graph_mem+y*vga_linewidth+x*vga_bytes; for(;ys;ys--){ memcpy(scr_start,data,xs*vga_bytes); data+=hndl->skip; scr_start+=vga_linewidth; } END_MOUSE } /* fill_area: 5,5,10,10 fills in 25 pixels! */ /* This assures that left, right, top, bottom will be sane according to the * clipping rectangle set up by svga_driver->set_clip_area. If empty region * results, return from current function occurs. */ #define FILL_CLIP_PREFACE \ int mouse_hidden;\ TEST_INACTIVITY\ if (left>=right||top>=bottom) return;\ if (left>=dev->clip.x2||right<=dev->clip.x1||top>=dev->clip.y2||bottom<=dev->clip.y1) return;\ if (leftclip.x1) left=dev->clip.x1;\ if (right>dev->clip.x2) right=dev->clip.x2;\ if (topclip.y1) top=dev->clip.y1;\ if (bottom>dev->clip.y2) bottom=dev->clip.y2;\ TEST_MOUSE(left,right,top,bottom) static void fill_area_accel_box(struct graphics_device *dev, int left, int top, int right, int bottom, long color) { FILL_CLIP_PREFACE vga_accel(ACCEL_SETFGCOLOR,color); vga_accel(ACCEL_FILLBOX,left,top,right-left,bottom-top); END_MOUSE } static void fill_area_accel_lines(struct graphics_device *dev, int left, int top, int right, int bottom, long color) { int y; FILL_CLIP_PREFACE vga_accel(ACCEL_SETFGCOLOR,color); for (y=top;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 left, int top, int right, int bottom, long color) { int dest; int y; int len; FILL_CLIP_PREFACE SYNC len=(right-left)*vga_bytes; dest=top*vga_linewidth+left*vga_bytes; for (y=bottom-top;y;y--){ pixel_set_paged(dest,len,&color); dest+=vga_linewidth; } END_MOUSE } #define HLINE_CLIP_PREFACE \ int mouse_hidden;\ TEST_INACTIVITY\ if (left>=right) return;\ if (yclip.y1||y>=dev->clip.y2||right<=dev->clip.x1||left>=dev->clip.x2) return;\ if (leftclip.x1) left=dev->clip.x1;\ if (right>dev->clip.x2) right=dev->clip.x2;\ TEST_MOUSE (left,right,y,y+1) #define VLINE_CLIP_PREFACE \ int mouse_hidden;\ TEST_INACTIVITY\ if (top>=bottom) return;\ if (xclip.x1||x>=dev->clip.x2||top>=dev->clip.y2||bottom<=dev->clip.y1) return;\ if (topclip.y1) top=dev->clip.y1;\ if (bottom>dev->clip.y2) bottom=dev->clip.y2;\ TEST_MOUSE(x,x+1,top,bottom) static void draw_hline_accel_line(struct graphics_device *dev, int left, int y, int right, long color) { HLINE_CLIP_PREFACE vga_accel(ACCEL_SETFGCOLOR,color); vga_accel(ACCEL_DRAWLINE,left,y,right-1,y); END_MOUSE } static void draw_hline_accel_box(struct graphics_device *dev, int left, int y, int right, long color) { HLINE_CLIP_PREFACE vga_accel(ACCEL_SETFGCOLOR,color); vga_accel(ACCEL_FILLBOX,left,y,right-left,1); END_MOUSE } static void draw_vline_accel_line(struct graphics_device *dev, int x, int top, int bottom, long color) { VLINE_CLIP_PREFACE vga_accel(ACCEL_SETFGCOLOR,color); vga_accel(ACCEL_DRAWLINE,x,top,x,bottom-1); END_MOUSE } static void draw_vline_accel_box(struct graphics_device *dev, int x, int top, int bottom, long color) { VLINE_CLIP_PREFACE vga_accel(ACCEL_SETFGCOLOR,color); vga_accel(ACCEL_FILLBOX,x,top,1,bottom-top); END_MOUSE } static void draw_hline_linear(struct graphics_device *dev, int left, int y, int right, long color) { unsigned char *dest; HLINE_CLIP_PREFACE SYNC dest=my_graph_mem+y*vga_linewidth+left*vga_bytes; pixel_set(dest,(right-left)*vga_bytes,&color); END_MOUSE } static void draw_vline_linear(struct graphics_device *dev, int x, int top, int bottom, long color) { unsigned char *dest; int y; VLINE_CLIP_PREFACE SYNC dest=my_graph_mem+top*vga_linewidth+x*vga_bytes; for (y=(bottom-top);y;y--){ memcpy(dest,&color,vga_bytes); dest+=vga_linewidth; } END_MOUSE } static void draw_hline_paged(struct graphics_device *dev, int left, int y, int right, long color) { int dest; int len; HLINE_CLIP_PREFACE SYNC len=(right-left)*vga_bytes; dest=y*vga_linewidth+left*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 top, int bottom, long color) { int dest,n, page,paga,remains; int byte=*(unsigned char *)&color; VLINE_CLIP_PREFACE; SYNC dest=top*vga_linewidth+x; n=bottom-top; 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 top, int bottom, long color) { int dest,page,n,paga,remains; int word=*(t2c *)do_not_optimize_here((void *)&color); VLINE_CLIP_PREFACE; SYNC dest=top*vga_linewidth+(x<<1); n=bottom-top; 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 top, int bottom, long color) { unsigned long dest,page,paga,remains,n; t4c val=*(t4c *)do_not_optimize_here((void *)&color); VLINE_CLIP_PREFACE; SYNC dest=top*(unsigned long)vga_linewidth+(x<<2); n=bottom-top; 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 top, int bottom, long color) { int dest,page,paga,remains,n; VLINE_CLIP_PREFACE; SYNC dest=top*vga_linewidth+x*vga_bytes; n=bottom-top; 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(my_graph_mem+paga,&color,vga_bytes); paga+=vga_linewidth; } vga_page=page; END_MOUSE return; }else{ dest+=remains*vga_linewidth; n-=remains; for (;remains;remains--){ memcpy(my_graph_mem+paga,&color,vga_bytes); 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 top, int bottom, 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=top*vga_linewidth+x*vga_bytes; n=bottom-top; 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(my_graph_mem+paga,&color,vga_bytes); paga+=vga_linewidth; } end: vga_page=page; END_MOUSE return; }else{ lina+=remains*vga_linewidth; n-=remains; for (;remains;remains--){ memcpy(my_graph_mem+paga,&color,vga_bytes); paga+=vga_linewidth; } if (paga>=65536)vga_setpage(++page); goto again; } } #define HSCROLL_CLIP_PREFACE \ int mouse_hidden;\ TEST_INACTIVITY_0\ if (!sc) return 0;\ if (sc>(dev->clip.x2-dev->clip.x1)||-sc>(dev->clip.x2-dev->clip.x1))\ return 1;\ TEST_MOUSE (dev->clip.x1,dev->clip.x2,dev->clip.y1,dev->clip.y2) /* When sc is <0, moves the data left. Scrolls the whole clip window */ static int hscroll_accel(struct graphics_device *dev, struct rect_set **ignore, int sc) { HSCROLL_CLIP_PREFACE if (sc>0){ /* Move data to the right */ vga_accel(ACCEL_SCREENCOPY,dev->clip.x1,dev->clip.y1,dev->clip.x1+sc,dev->clip.y1 ,dev->clip.x2-dev->clip.x1-sc,dev->clip.y2-dev->clip.y1); }else{ /* Move data to the left */ vga_accel(ACCEL_SCREENCOPY,dev->clip.x1-sc,dev->clip.y1,dev->clip.x1,dev->clip.y1 ,dev->clip.x2-dev->clip.x1+sc,dev->clip.y2-dev->clip.y1); } END_MOUSE return 1; } #define VSCROLL_CLIP_PREFACE \ int mouse_hidden;\ TEST_INACTIVITY_0\ if (!sc) return 0;\ if (sc>dev->clip.y2-dev->clip.y1||-sc>dev->clip.y2-dev->clip.y1) return 1;\ TEST_MOUSE (dev->clip.x1, dev->clip.x2, dev->clip.y1, dev->clip.y2) /* Positive sc means data move down */ static int vscroll_accel(struct graphics_device *dev, struct rect_set **ignore, int sc) { VSCROLL_CLIP_PREFACE if (sc>0){ /* Move down */ vga_accel(ACCEL_SCREENCOPY,dev->clip.x1,dev->clip.y1,dev->clip.x1,dev->clip.y1+sc ,dev->clip.x2-dev->clip.x1,dev->clip.y2-dev->clip.y1-sc); }else{ /* Move up */ vga_accel(ACCEL_SCREENCOPY,dev->clip.x1,dev->clip.y1-sc,dev->clip.x1,dev->clip.y1 ,dev->clip.x2-dev->clip.x1,dev->clip.y2-dev->clip.y1+sc); } END_MOUSE return 1; } static int hscroll_scansegment(struct graphics_device *dev, struct rect_set **ignore, int sc) { int y; int len; HSCROLL_CLIP_PREFACE SYNC if (sc>0){ /* Right */ len=dev->clip.x2-dev->clip.x1-sc; for (y=dev->clip.y1;yclip.y2;y++){ vga_getscansegment(scroll_buffer,dev->clip.x1,y,len); vga_drawscansegment(scroll_buffer,dev->clip.x1+sc,y,len); } }else{ /* Left */ len=dev->clip.x2-dev->clip.x1+sc; for (y=dev->clip.y1;yclip.y2;y++){ vga_getscansegment(scroll_buffer,dev->clip.x1-sc,y,len); vga_drawscansegment(scroll_buffer,dev->clip.x1,y,len); } } END_MOUSE return 1; } static int hscroll_linear(struct graphics_device *dev, struct rect_set **ignore, int sc) { unsigned char *dest, *src; int y; int len; HSCROLL_CLIP_PREFACE SYNC if (sc>0){ len=(dev->clip.x2-dev->clip.x1-sc)*vga_bytes; src=my_graph_mem+vga_linewidth*dev->clip.y1+dev->clip.x1*vga_bytes; dest=src+sc*vga_bytes; for (y=dev->clip.y2-dev->clip.y1;y;y--){ memmove(dest,src,len); dest+=vga_linewidth; src+=vga_linewidth; } }else{ len=(dev->clip.x2-dev->clip.x1+sc)*vga_bytes; dest=my_graph_mem+vga_linewidth*dev->clip.y1+dev->clip.x1*vga_bytes; src=dest-sc*vga_bytes; for (y=dev->clip.y2-dev->clip.y1;y;y--){ memmove(dest,src,len); dest+=vga_linewidth; src+=vga_linewidth; } } END_MOUSE return 1; } static int vscroll_scansegment(struct graphics_device *dev, struct rect_set **ignore, int sc) { int y; int len; VSCROLL_CLIP_PREFACE SYNC len=dev->clip.x2-dev->clip.x1; if (sc>0){ /* Down */ for (y=dev->clip.y2-1;y>=dev->clip.y1+sc;y--){ vga_getscansegment(scroll_buffer, dev->clip.x1,y-sc,len); vga_drawscansegment(scroll_buffer,dev->clip.x1,y,len); } }else{ /* Up */ for (y=dev->clip.y1-sc;yclip.y2;y++){ vga_getscansegment(scroll_buffer,dev->clip.x1,y,len); vga_drawscansegment(scroll_buffer, dev->clip.x1,y+sc,len); } } END_MOUSE return 1; } static int vscroll_linear(struct graphics_device *dev, struct rect_set **ignore, int sc) { unsigned char *dest, *src; int y; int len; VSCROLL_CLIP_PREFACE SYNC len=(dev->clip.x2-dev->clip.x1)*vga_bytes; if (sc>0){ /* Down */ dest=my_graph_mem+(dev->clip.y2-1)*vga_linewidth+dev->clip.x1*vga_bytes; src=dest-vga_linewidth*sc; for (y=dev->clip.y2-dev->clip.y1-sc;y;y--){ memcpy(dest,src,len); 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*sc; for (y=dev->clip.y2-dev->clip.y1+sc;y;y--){ memcpy(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 vscroll_paged(struct graphics_device *dev, struct rect_set **ignore, int sc) { int dest,src; int y; int len; VSCROLL_CLIP_PREFACE SYNC len=(dev->clip.x2-dev->clip.x1)*vga_bytes; if (sc>0){ /* Down */ dest=(dev->clip.y2-1)*vga_linewidth+dev->clip.x1*vga_bytes; src=dest-vga_linewidth*sc; for (y=dev->clip.y2-dev->clip.y1-sc;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*sc; for (y=dev->clip.y2-dev->clip.y1+sc;y;y--){ get_row(scroll_buffer, src,len); paged_memcpy(dest,scroll_buffer,len); dest+=vga_linewidth; src+=vga_linewidth; } } END_MOUSE return 1; } static int hscroll_paged(struct graphics_device *dev, struct rect_set **ignore, int sc) { int dest,src; int y; int len; HSCROLL_CLIP_PREFACE SYNC if (sc>0){ len=(dev->clip.x2-dev->clip.x1-sc)*vga_bytes; src=vga_linewidth*dev->clip.y1+dev->clip.x1*vga_bytes; dest=src+sc*vga_bytes; for (y=dev->clip.y2-dev->clip.y1;y;y--){ get_row(scroll_buffer, src,len); paged_memcpy(dest,scroll_buffer,len); dest+=vga_linewidth; src+=vga_linewidth; } }else{ len=(dev->clip.x2-dev->clip.x1+sc)*vga_bytes; dest=vga_linewidth*dev->clip.y1+dev->clip.x1*vga_bytes; src=dest-sc*vga_bytes; for (y=dev->clip.y2-dev->clip.y1;y;y--){ get_row(scroll_buffer, src,len); paged_memcpy(dest,scroll_buffer,len); dest+=vga_linewidth; src+=vga_linewidth; } } END_MOUSE return 1; } static void svga_set_clip_area(struct graphics_device *dev, struct rect *r) { memcpy(&dev->clip, r, sizeof(struct rect)); if (dev->clip.x1>=dev->clip.x2||dev->clip.y2<=dev->clip.y1||dev->clip.y2<=0||dev->clip.x2<=0||dev->clip.x1>=xsize ||dev->clip.y1>=ysize){ /* Empty region */ dev->clip.x1=dev->clip.x2=dev->clip.y1=dev->clip.y2=0; }else{ if (dev->clip.x1<0) dev->clip.x1=0; if (dev->clip.x2>xsize) dev->clip.x2=xsize; if (dev->clip.y1<0) dev->clip.y1=0; if (dev->clip.y2>ysize) dev->clip.y2=ysize; } } /* For modes where video memory is not directly accessible through svgalib */ static inline void fill_area_drawscansegment(struct graphics_device *dev, int left, int top, int right, int bottom, long color) { int xs; int col=*(unsigned char *)&color; FILL_CLIP_PREFACE SYNC xs=right-left; memset(scroll_buffer,col,xs); for (;top=xsize||y>ysize) return; while(x+(*hndls)->x<=0&&n){ x+=(*hndls)->x; n--; hndls++; } draw_b = svga_driver.draw_bitmap; while(n&&x<=xsize){ draw_b(dev, *hndls, x, y); x+=(*hndls)->x; n--; hndls++; } } #endif 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) { 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("Unknown bit depth %x", svga_driver.depth); switch(vga_colors){ case 2: internal( "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.hscroll=hscroll_scansegment; svga_driver.vscroll=vscroll_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.hscroll=hscroll_accel; svga_driver.vscroll=vscroll_accel; }else if (vga_linear){ svga_driver.hscroll=hscroll_linear; svga_driver.vscroll=vscroll_linear; svga_driver.flags |= GD_DONT_USE_SCROLL; }else if (mode_x){ alloc_scroll_buffer(); svga_driver.hscroll=hscroll_scansegment; svga_driver.vscroll=vscroll_scansegment; svga_driver.flags |= GD_DONT_USE_SCROLL; }else{ alloc_scroll_buffer(); svga_driver.hscroll=hscroll_paged; svga_driver.vscroll=vscroll_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(void *p, struct event *ev, int size) { if (size != sizeof(struct event)) return; if (ev->ev == EV_ABORT) terminate_loop = 1; if (ev->ev != EV_KBD) return; if ((ev->y & KBD_ALT) && ev->x >= '0' && ev->x <= '9') { switch_virtual_device((ev->x - '1' + 10) % 10); return; } if (svga_driver.codepage!=utf8_table&&(ev->x)>=128&&(ev->x)<=255) if ((ev->x=cp2u(ev->x,svga_driver.codepage)) == -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) return; if (!current_virtual_device->mouse_handler) return; current_virtual_device->mouse_handler(current_virtual_device, mouse_x, mouse_y, mouse_aggregate_action); } /* Only calls appropriate callbacks, doesn't draw anything. */ static void mouse_event_handler(int button, int dx, int dy, int dz, int drx, int dry, int drz) { 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: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; bmp.x=arrow_width; bmp.y=arrow_height; bmp.skip=arrow_width*fb_pixelsize; bmp.data=background_buffer; { struct graphics_device * current_virtual_device_backup; 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; 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; bmp.x=arrow_width; bmp.y=arrow_height; bmp.skip=arrow_width*fb_pixelsize; bmp.data=mouse_buffer; { struct graphics_device * current_graphics_device_backup; 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_bottombytesperpixel; 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; aspect_native=(196608*xsize+(ysize<<1))/(ysize<<2); aspect=aspect_native*bfu_aspect+0.5; vga_colors=i->colors; if (xsize==320&&ysize==200&&vga_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); /*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; 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 (!oktowrite&&!flags){ backup_virtual_device=current_virtual_device; current_virtual_device=NULL; } if (flags==1&&oktowrite) current_virtual_device=backup_virtual_device; flags=(flags&~1)|!oktowrite; svgalib_timer_id=install_timer(100,vtswitch_handler, NULL); } #endif static void svga_ctrl_c(struct itrm *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=1) vga_runinbackground(1); #endif if (vga_setmode(modes[j].number) < 0) { #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((void (*)(void *, unsigned char *, int))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(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, (void (*)(void *))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_filled_bitmap(struct bitmap *dest, long color) { int n; if (dest->x && (unsigned)dest->x * (unsigned)dest->y / (unsigned)dest->x != (unsigned)dest->y) overalloc(); if ((unsigned)dest->x * (unsigned)dest->y > MAXINT / fb_pixelsize) overalloc(); n=dest->x*dest->y*fb_pixelsize; dest->data=mem_alloc(n); pixel_set(dest->data,n,&color); dest->skip=dest->x*fb_pixelsize; dest->flags=0; return 0; } */ /* 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){ if (!(flags&1)){ backup_virtual_device=current_virtual_device; current_virtual_device=NULL; } svgalib_block_itrm(svgalib_kbd); if (mouse_works){ hide_mouse(); /* mouse_close(); This is not necessary as it is handled by vga_setmode(TEXT). */ } if (vga_setmode(TEXT) < 0) { error("ERROR: vga_setmode failed"); fatal_tty_exit(); exit(RET_FATAL); } } flags|=2; return overridden; } static int vga_unblock(struct graphics_device *dev) { #ifdef DEBUG if (current_virtual_device) { internal("vga_unblock called without vga_block"); return 0; } #endif /* #ifdef DEBUG */ flags&=~2; if (!flags) current_virtual_device=backup_virtual_device; vga_setmousesupport(1); if (vga_setmode(vga_mode) < 0) { error("ERROR: vga_setmode failed"); fatal_tty_exit(); exit(RET_FATAL); } setup_mode(vga_mode); if (mouse_works){ show_mouse(); mouse_seteventhandler(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; } /* This is a nasty hack */ #undef select 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) { struct rect r; r.x1 = 0; r.y1 = 0; r.x2 = svga_driver.x; r.y2 = svga_driver.y; if (current_virtual_device) current_virtual_device->redraw_handler(current_virtual_device,&r); 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