diff options
Diffstat (limited to 'framebuffer.c')
-rw-r--r-- | framebuffer.c | 1685 |
1 files changed, 1685 insertions, 0 deletions
diff --git a/framebuffer.c b/framebuffer.c new file mode 100644 index 0000000..6582b8b --- /dev/null +++ b/framebuffer.c @@ -0,0 +1,1685 @@ +/* framebuffer.c + * Linux framebuffer code + * (c) 2002 Petr 'Brain' Kulhavy + * This file is a part of the Links program, released under GPL. + */ + +#include "cfg.h" + +#ifdef GRDRV_FB + +#define USE_GPM_DX + +/* #define FB_DEBUG */ +/* #define SC_DEBUG */ + +/* note: SIGUSR1 is used by libpthread and is disabled even if no thread + functions are called --- do not use */ + +#define SIG_REL SIGUSR2 +#define SIG_ACQ SIGVTALRM + +#if defined(FB_DEBUG) || defined(SC_DEBUG) + #define MESSAGE(a) fprintf(stderr,"%s",a); +#endif + +#include "links.h" + +#include "bits.h" + +#include <gpm.h> + +#include <sys/mman.h> +#include <sys/ioctl.h> + +#include <linux/fb.h> +#include <linux/kd.h> +#include <linux/vt.h> + +#include "arrow.inc" + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1L) +#endif + +#ifdef GPM_HAVE_SMOOTH +#define gpm_smooth GPM_SMOOTH +#else +#define gpm_smooth 0 +#endif + +static int TTY = 0; + +#ifndef USE_GPM_DX +static int fb_txt_xsize, fb_txt_ysize; +static struct winsize fb_old_ws; +static struct winsize fb_new_ws; +static int fb_old_ws_v; +static int fb_msetsize; +#endif +static int fb_hgpm; + +static int fb_console; + +static struct itrm *fb_kbd; + +static struct graphics_device *fb_old_vd; +static struct graphics_device *fb_block_dev; + +static int fb_handler; +static unsigned char *fb_mem, *fb_vmem; +static unsigned fb_mem_size; +static unsigned fb_mapped_size; +static int fb_linesize,fb_bits_pp,fb_pixelsize; +static int fb_xsize,fb_ysize; +static long border_left, border_right, border_top, border_bottom; +static int fb_colors, fb_palette_colors; +static struct fb_var_screeninfo vi; +static struct fb_fix_screeninfo fi; + +static void fb_draw_bitmap(struct graphics_device *dev,struct bitmap* hndl, int x, int y); + +static unsigned char *fb_driver_param; +struct graphics_driver fb_driver; +static int have_cmap=0; +static volatile int fb_active=1; + +struct palette +{ + unsigned short *red; + unsigned short *green; + unsigned short *blue; +}; + +static struct palette old_palette; +static struct palette global_pal; +static struct vt_mode vt_mode,vt_omode; + +static struct fb_var_screeninfo oldmode; + +static volatile int in_gr_operation; + +/* mouse */ +static int mouse_x, mouse_y; /* mouse pointer coordinates */ +static long mouse_black, mouse_white; +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; + + +#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(); + +#define END_GR \ + in_gr_operation--;\ + if (!fb_active && !in_gr_operation)\ + EINTRLOOP(rs, ioctl(TTY,VT_RELDISP,1)); +#define START_GR \ + in_gr_operation++; \ + if (!fb_active) { END_GR; return; } +#define START_GR_0 \ + in_gr_operation++; \ + if (!fb_active) { END_GR; return 0; } + + +#define NUMBER_OF_DEVICES 10 + +#define TEST_INACTIVITY if (!fb_active||dev!=current_virtual_device) return; + +#define TEST_INACTIVITY_0 if (!fb_active||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)) + +/* 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 mouse_hidden;\ + int xs=hndl->x,ys=hndl->y;\ + unsigned char *data=hndl->data;\ +\ + 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\ + */\ + START_GR\ + TEST_MOUSE (x,x+xs,y,y+ys) + + +/* 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 (left<dev->clip.x1) left=dev->clip.x1;\ + if (right>dev->clip.x2) right=dev->clip.x2;\ + if (top<dev->clip.y1) top=dev->clip.y1;\ + if (bottom>dev->clip.y2) bottom=dev->clip.y2;\ + START_GR\ + TEST_MOUSE(left,right,top,bottom) + + +#define HLINE_CLIP_PREFACE \ + int mouse_hidden;\ + TEST_INACTIVITY\ + if (y<dev->clip.y1||y>=dev->clip.y2||right<=dev->clip.x1||left>=dev->clip.x2) return;\ + if (left<dev->clip.x1) left=dev->clip.x1;\ + if (right>dev->clip.x2) right=dev->clip.x2;\ + if (left>=right) return;\ + START_GR\ + TEST_MOUSE (left,right,y,y+1) + +#define VLINE_CLIP_PREFACE \ + int mouse_hidden;\ + TEST_INACTIVITY\ + if (x<dev->clip.x1||x>=dev->clip.x2||top>=dev->clip.y2||bottom<=dev->clip.y1) return;\ + if (top<dev->clip.y1) top=dev->clip.y1;\ + if (bottom>dev->clip.y2) bottom=dev->clip.y2;\ + if (top>=bottom) return;\ + START_GR\ + TEST_MOUSE(x,x+1,top,bottom) + +#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;\ + START_GR_0\ + TEST_MOUSE (dev->clip.x1,dev->clip.x2,dev->clip.y1,dev->clip.y2) + +#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;\ + START_GR_0\ + TEST_MOUSE (dev->clip.x1, dev->clip.x2, dev->clip.y1, dev->clip.y2)\ + +#include "fbcommon.inc" + +static void redraw_mouse(void); + +static void fb_mouse_move(int dx, int dy) +{ + struct event ev; + mouse_x += dx; + mouse_y += dy; + ev.ev = EV_MOUSE; + if (mouse_x >= fb_xsize) mouse_x = fb_xsize - 1; + if (mouse_y >= fb_ysize) mouse_y = fb_ysize - 1; + if (mouse_x < 0) mouse_x = 0; + if (mouse_y < 0) mouse_y = 0; + ev.x = mouse_x; + ev.y = mouse_y; + ev.b = B_MOVE; + if (!current_virtual_device) return; + if (current_virtual_device->mouse_handler) current_virtual_device->mouse_handler(current_virtual_device, ev.x, ev.y, ev.b); + redraw_mouse(); +} + +static void fb_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 (!current_virtual_device) return; + if (!ev->y && ev->x == KBD_F5) fb_mouse_move(-3, 0); + else if (!ev->y && ev->x == KBD_F6) fb_mouse_move(0, 3); + else if (!ev->y && ev->x == KBD_F7) fb_mouse_move(0, -3); + else if (!ev->y && ev->x == KBD_F8) fb_mouse_move(3, 0); + else + { + if (fb_driver.codepage!=utf8_table&&(ev->x)>=128&&(ev->x)<=255) + if ((ev->x=cp2u(ev->x,fb_driver.codepage)) == -1) return; + if (current_virtual_device->keyboard_handler) current_virtual_device->keyboard_handler(current_virtual_device, ev->x, ev->y); + } +} + + + + +#define mouse_getscansegment(buf,x,y,w) memcpy(buf,fb_vmem+y*fb_linesize+x*fb_pixelsize,w) +#define mouse_drawscansegment(ptr,x,y,w) memcpy(fb_vmem+y*fb_linesize+x*fb_pixelsize,ptr,w); + +/* 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; + fb_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>fb_xsize?fb_xsize-x:arrow_width); + height=arrow_height+y>fb_ysize?fb_ysize-y:arrow_height; + + 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; + fb_draw_bitmap(mouse_graphics_device, &bmp, mouse_x, mouse_y); + current_virtual_device=current_graphics_device_backup; + } + global_mouse_hidden=0; +} + +/* Only when the old and the new mouse positions do not interfere. Using this routine + * on interfering positions would cause a flicker. + */ +static void show_mouse(void) +{ + + get_mouse_background(background_buffer); + background_x=mouse_x; + background_y=mouse_y; + memcpy(mouse_buffer,background_buffer,fb_pixelsize*arrow_area); + render_mouse_arrow(); + place_mouse(); +} + +/* Doesn't draw anything into the screen + */ +static void put_and_clip_background_buffer_over_mouse_buffer(void) +{ + unsigned char *bbufptr=background_buffer, *mbufptr=mouse_buffer; + int left=background_x-mouse_x; + int top=background_y-mouse_y; + int right,bottom; + int bmpixelsizeL=fb_pixelsize; + int number_of_bytes; + int byte_skip; + + right=left+arrow_width; + bottom=top+arrow_height; + + if (left<0){ + bbufptr-=left*bmpixelsizeL; + left=0; + } + if (right>arrow_width) right=arrow_width; + if (top<0){ + bbufptr-=top*bmpixelsizeL*arrow_width; + top=0; + } + if (bottom>arrow_height) bottom=arrow_height; + mbufptr+=bmpixelsizeL*(left+arrow_width*top); + byte_skip=arrow_width*bmpixelsizeL; + number_of_bytes=bmpixelsizeL*(right-left); + for (;top<bottom;top++){ + memcpy(mbufptr,bbufptr,number_of_bytes); + mbufptr+=byte_skip; + bbufptr+=byte_skip; + } +} + +/* This draws both the contents of background_buffer and mouse_buffer in a scan + * way (left-right, top-bottom), so the flicker is reduced. + */ +static inline void place_mouse_composite(void) +{ + int mouse_left=mouse_x; + int mouse_top=mouse_y; + int background_left=background_x; + int background_top=background_y; + int mouse_right=mouse_left+arrow_width; + int mouse_bottom=mouse_top+arrow_height; + int background_right=background_left+arrow_width; + int background_bottom=background_top+arrow_height; + int skip=arrow_width*fb_pixelsize; + int background_length,mouse_length; + unsigned char *mouse_ptr=mouse_buffer,*background_ptr=background_buffer; + int yend; + + if (mouse_bottom>fb_ysize) mouse_bottom=fb_ysize; + if (background_bottom>fb_ysize) background_bottom=fb_ysize; + + /* Let's do the top part */ + if (background_top<mouse_top){ + /* Draw the background */ + background_length=background_right>fb_xsize?fb_xsize-background_left + :arrow_width; + for (;background_top<mouse_top;background_top++){ + mouse_drawscansegment(background_ptr,background_left + ,background_top,background_length*fb_pixelsize); + background_ptr+=skip; + } + + }else if (background_top>mouse_top){ + /* Draw the mouse */ + mouse_length=mouse_right>fb_xsize + ?fb_xsize-mouse_left:arrow_width; + for (;mouse_top<background_top;mouse_top++){ + mouse_drawscansegment(mouse_ptr,mouse_left,mouse_top,mouse_length*fb_pixelsize); + mouse_ptr+=skip; + } + } + + /* Let's do the middle part */ + yend=mouse_bottom<background_bottom?mouse_bottom:background_bottom; + if (background_left<mouse_left){ + /* Draw background, mouse */ + mouse_length=mouse_right>fb_xsize?fb_xsize-mouse_left:arrow_width; + for (;mouse_top<yend;mouse_top++){ + mouse_drawscansegment(background_ptr,background_left,mouse_top + ,(mouse_left-background_left)*fb_pixelsize); + mouse_drawscansegment(mouse_ptr,mouse_left,mouse_top,mouse_length*fb_pixelsize); + mouse_ptr+=skip; + background_ptr+=skip; + } + + }else{ + int l1, l2, l3; + + /* Draw mouse, background */ + mouse_length=mouse_right>fb_xsize?fb_xsize-mouse_left:arrow_width; + background_length=background_right-mouse_right; + if (background_length+mouse_right>fb_xsize) + background_length=fb_xsize-mouse_right; + l1=mouse_length*fb_pixelsize; + l2=(mouse_right-background_left)*fb_pixelsize; + l3=background_length*fb_pixelsize; + for (;mouse_top<yend;mouse_top++){ + mouse_drawscansegment(mouse_ptr,mouse_left,mouse_top,l1); + if (background_length>0) + mouse_drawscansegment( + background_ptr +l2, + mouse_right,mouse_top ,l3); + mouse_ptr+=skip; + background_ptr+=skip; + } + } + + if (background_bottom<mouse_bottom){ + /* Count over bottoms! tops will be invalid! */ + /* Draw mouse */ + mouse_length=mouse_right>fb_xsize?fb_xsize-mouse_left + :arrow_width; + for (;background_bottom<mouse_bottom;background_bottom++){ + mouse_drawscansegment(mouse_ptr,mouse_left,background_bottom + ,mouse_length*fb_pixelsize); + mouse_ptr+=skip; + } + }else{ + /* Draw background */ + background_length=background_right>fb_xsize?fb_xsize-background_left + :arrow_width; + for (;mouse_bottom<background_bottom;mouse_bottom++){ + mouse_drawscansegment(background_ptr,background_left,mouse_bottom + ,background_length*fb_pixelsize); + background_ptr+=skip; + } + } +} + +/* This moves the mouse a sophisticated way when the old and new position of the + * cursor overlap. + */ +static inline void redraw_mouse_sophisticated(void) +{ + int new_background_x, new_background_y; + + get_mouse_background(mouse_buffer); + put_and_clip_background_buffer_over_mouse_buffer(); + memcpy(new_background_buffer,mouse_buffer,fb_pixelsize*arrow_area); + new_background_x=mouse_x; + new_background_y=mouse_y; + render_mouse_arrow(); + place_mouse_composite(); + memcpy(background_buffer,new_background_buffer,fb_pixelsize*arrow_area); + background_x=new_background_x; + background_y=new_background_y; +} + +static void redraw_mouse(void){ + + if (!fb_active) return; /* We are not drawing */ + if (mouse_x!=background_x||mouse_y!=background_y){ + if (RECTANGLES_INTERSECT( + background_x, background_x+arrow_width, + mouse_x, mouse_x+arrow_width, + background_y, background_y+arrow_height, + mouse_y, mouse_y+arrow_height)){ + redraw_mouse_sophisticated(); + }else{ + /* Do a normal hide/show */ + get_mouse_background(mouse_buffer); + memcpy(new_background_buffer, + mouse_buffer,arrow_area*fb_pixelsize); + render_mouse_arrow(); + hide_mouse(); + place_mouse(); + memcpy(background_buffer,new_background_buffer + ,arrow_area*fb_pixelsize); + background_x=mouse_x; + background_y=mouse_y; + } + } +} + +/* 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 palette *palette) +{ + int a; + + switch (fb_colors) + { + case 16: + for (a=0;a<fb_palette_colors;a++) + { + palette->red[a]=(a&8)?65535:0; + palette->green[a]=((a>>1)&3)*(65535/3); + palette->blue[a]=(a&1)?65535:0; + } + break; + case 256: + for (a=0;a<fb_palette_colors;a++){ + palette->red[a]=((a>>5)&7)*(65535/7); + palette->green[a]=((a>>2)&7)*(65535/7); + palette->blue[a]=(a&3)*(65535/3); + } + break; + case 32768: + for (a=0;a<fb_palette_colors;a++){ + /* + palette->red[a]=((a>>10)&31)*(65535/31); + palette->green[a]=((a>>5)&31)*(65535/31); + palette->blue[a]=(a&31)*(65535/31); + */ + palette->red[a]= + palette->green[a]= + palette->blue[a]=(((a&31)*255)/31)*257; + } + break; + case 65536: + for (a=0;a<fb_palette_colors;a++){ + /* + palette->red[a]=((a>>11)&31)*(65535/31); + palette->green[a]=((a>>5)&63)*(65535/63); + palette->blue[a]=(a&31)*(65535/31); + */ + palette->green[a]=(((a&63)*255)/64)*257; + palette->red[a]= + palette->blue[a]=(((a&31)*255)/32)*257; + } + break; + default: + for (a=0;a<fb_palette_colors;a++){ + palette->red[a]= + palette->green[a]= + palette->blue[a]=a*257; + /* stuff it in both high and low byte */ + } + } +} + +static void alloc_palette(struct palette *pal) +{ + pal->red=mem_calloc(sizeof(unsigned short)*fb_palette_colors); + pal->green=mem_calloc(sizeof(unsigned short)*fb_palette_colors); + pal->blue=mem_calloc(sizeof(unsigned short)*fb_palette_colors); + + if (!pal->red||!pal->green||!pal->blue) { + /*internal("Cannot create palette.\n")*/; + } +} + + +static void free_palette(struct palette *pal) +{ + mem_free(pal->red); + mem_free(pal->green); + mem_free(pal->blue); +} + + +static void set_palette(struct palette *pal) +{ + struct fb_cmap cmap; + int i; + unsigned short *red=pal->red; + unsigned short *green=pal->green; + unsigned short *blue=pal->blue; + __u16 *r, *g, *b, *t; + int rs; + + r=mem_alloc(fb_palette_colors*sizeof(__u16)); + g=mem_alloc(fb_palette_colors*sizeof(__u16)); + b=mem_alloc(fb_palette_colors*sizeof(__u16)); + t=mem_calloc(fb_palette_colors*sizeof(__u16)); + + if (!r||!g||!b||!t) { + /*internal("Cannot allocate memory.\n")*/; + } + + for (i = 0; i < fb_palette_colors; i++) + { + r[i] = red[i]; + g[i] = green[i]; + b[i] = blue[i]; + /*fprintf(stderr, "%d %d %d\n", r[i], g[i], b[i]);*/ + /*fprintf(stderr, "%5x: %5x\t%5x\t%5x\t%5x\n",i,r[i],g[i],b[i],t[i]);*/ + + } + + cmap.start = 0; + cmap.len = fb_palette_colors; + cmap.red = r; + cmap.green = g; + cmap.blue = b; + cmap.transp = t; + + EINTRLOOP(rs, ioctl(fb_handler, FBIOPUTCMAP, &cmap)); + if (rs==-1) { + /*internal("Cannot set palette\n")*/; + } + + mem_free(r);mem_free(g);mem_free(b);mem_free(t); +} + + +static void get_palette(struct palette *pal) +{ + struct fb_cmap cmap; + int i; + __u16 *r, *g, *b, *t; + int rs; + + r=mem_alloc(fb_palette_colors*sizeof(__u16)); + g=mem_alloc(fb_palette_colors*sizeof(__u16)); + b=mem_alloc(fb_palette_colors*sizeof(__u16)); + t=mem_alloc(fb_palette_colors*sizeof(__u16)); + + if (!r||!g||!b||!t) { + /*internal("Cannot allocate memory.\n")*/; + } + + cmap.start = 0; + cmap.len = fb_palette_colors; + cmap.red = r; + cmap.green = g; + cmap.blue = b; + cmap.transp = t; + + EINTRLOOP(rs, ioctl(fb_handler, FBIOGETCMAP, &cmap)); + if (rs==-1) { + /*internal("Cannot get palette\n")*/; + } + + for (i = 0; i < fb_palette_colors; i++) + { + /*printf("%d %d %d\n",r[i],g[i],b[i]);*/ + pal->red[i] = r[i]; + pal->green[i] = g[i]; + pal->blue[i] = b[i]; + } + + mem_free(r);mem_free(g);mem_free(b);mem_free(t); +} + +static void fb_clear_videoram(void) +{ + memset(fb_mem, 0, (border_top + fb_ysize + border_bottom) * fb_linesize); +} + +static void sleep_a_little_bit(void) +{ + struct timeval tv = { 0, 20000 }; + fd_set dummy; + int rs; + FD_ZERO(&dummy); + EINTRLOOP(rs, select(0, &dummy, &dummy, &dummy, &tv)); +} + +static void fb_switch_signal(void *data) +{ + struct vt_stat st; + struct rect r; + int sign=(int)(unsigned long)data; + int rs; + + switch(sign) + { + case SIG_REL: /* release */ + fb_active=0; + if (!in_gr_operation) + EINTRLOOP(rs, ioctl(TTY,VT_RELDISP,1)); + break; + + case SIG_ACQ: /* acq */ + EINTRLOOP(rs, ioctl(TTY,VT_GETSTATE,&st)); + if (rs) return; + if (st.v_active != fb_console) return; + fb_active=1; + EINTRLOOP(rs, ioctl(TTY,VT_RELDISP,VT_ACKACQ)); + /* + * There is a race condition in Linux NVidia framebuffer driver + * It still draws into a framebuffer here, so we have to sleep + */ + sleep_a_little_bit(); + if (have_cmap && current_virtual_device) + set_palette(&global_pal); + r.x1=0; + r.y1=0; + r.x2=fb_xsize; + r.y2=fb_ysize; + if (border_left | border_top | border_right | border_bottom) fb_clear_videoram(); + if (current_virtual_device) current_virtual_device->redraw_handler(current_virtual_device,&r); + break; + } +} + + +static unsigned char *fb_switch_init(void) +{ + int rs; + + EINTRLOOP(rs, ioctl(TTY, VT_WAITACTIVE, fb_console)); + install_signal_handler(SIG_REL, fb_switch_signal, (void*)SIG_REL, 1); + install_signal_handler(SIG_ACQ, fb_switch_signal, (void*)SIG_ACQ, 0); + EINTRLOOP(rs, ioctl(TTY,VT_GETMODE, &vt_omode)); + if (rs == -1) { + return stracpy("Could not get VT mode.\n"); + } + memcpy(&vt_mode, &vt_omode, sizeof(vt_mode)); + + vt_mode.mode = VT_PROCESS; + vt_mode.waitv = 0; + vt_mode.relsig = SIG_REL; + vt_mode.acqsig = SIG_ACQ; + + EINTRLOOP(rs, ioctl(TTY,VT_SETMODE, &vt_mode)); + if (rs == -1) { + return stracpy("Could not set VT mode.\n"); + } + return NULL; +} + +static void fb_switch_shutdown(void) +{ + int rs; + EINTRLOOP(rs, ioctl(TTY,VT_SETMODE, &vt_omode)); +} + +static void fb_shutdown_palette(void) +{ + if (have_cmap) + { + set_palette(&old_palette); + free_palette(&old_palette); + free_palette(&global_pal); + } +} + +static void fb_ctrl_c(struct itrm *i) +{ + kbd_ctrl_c(); +} + +#ifndef USE_GPM_DX +static void fb_mouse_setsize(void) +{ + struct vt_stat vs; + int rs; + EINTRLOOP(rs, ioctl(0, VT_GETSTATE, &vs)); + if (!rs) { + fd_set zero; + struct timeval tv; + FD_ZERO(&zero); + memset(&tv, 0, sizeof tv); + EINTRLOOP(rs, ioctl(0, VT_ACTIVATE, vs.v_active > 1 ? 1 : 2)); + tv.tv_sec = 0; + tv.tv_usec = 100000; + EINTRLOOP(rs, select(0, &zero, &zero, &zero, &tv)); + tv.tv_sec = 0; + tv.tv_usec = 100000; + EINTRLOOP(rs, select(0, &zero, &zero, &zero, &tv)); + tv.tv_sec = 0; + tv.tv_usec = 100000; + EINTRLOOP(rs, select(0, &zero, &zero, &zero, &tv)); + EINTRLOOP(rs, ioctl(0, VT_ACTIVATE, vs.v_active)); + } +} +#endif + +static void unhandle_fb_mouse(void); + +static void fb_gpm_in(void *nic) +{ +#ifndef USE_GPM_DX + static int lx = -1, ly = -1; +#endif + struct event ev; + Gpm_Event gev; + again: + if (Gpm_GetEvent(&gev) <= 0) { + unhandle_fb_mouse(); + return; + } + /*fprintf(stderr, "%d %d\n", gev.x, gev.y);*/ +#ifndef USE_GPM_DX + if (gev.x != lx || gev.y != ly) { + mouse_x = (gev.x - 1) * fb_xsize / fb_txt_xsize + fb_xsize / fb_txt_xsize / 2 - 1; + mouse_y = (gev.y - 1) * fb_ysize / fb_txt_ysize + fb_ysize / fb_txt_ysize / 2 - 1; + lx = gev.x, ly = gev.y; + } +#else + if (gev.dx || gev.dy) { + if (!(gev.type & gpm_smooth)) { + mouse_x += gev.dx * 8; + mouse_y += gev.dy * 8; + } else { + mouse_x += gev.dx; + mouse_y += gev.dy; + } + } +#endif + ev.ev = EV_MOUSE; + if (mouse_x >= fb_xsize) mouse_x = fb_xsize - 1; + if (mouse_y >= fb_ysize) mouse_y = fb_ysize - 1; + if (mouse_x < 0) mouse_x = 0; + if (mouse_y < 0) mouse_y = 0; + + if (!(gev.type & gpm_smooth) && (gev.dx || gev.dy)) { + mouse_x = (mouse_x + 8) / 8 * 8 - 4; + mouse_y = (mouse_y + 8) / 8 * 8 - 4; + if (mouse_x >= fb_xsize) mouse_x = fb_xsize - 1; + if (mouse_y >= fb_ysize) mouse_y = fb_ysize - 1; + if (mouse_x < 0) mouse_x = 0; + if (mouse_y < 0) mouse_y = 0; + } + + ev.x = mouse_x; + ev.y = mouse_y; + if (gev.buttons & GPM_B_LEFT) ev.b = B_LEFT; + else if (gev.buttons & GPM_B_MIDDLE) ev.b = B_MIDDLE; + else if (gev.buttons & GPM_B_RIGHT) ev.b = B_RIGHT; + else ev.b = 0; + if (gev.type & GPM_DOWN) ev.b |= B_DOWN; + else if (gev.type & GPM_UP) ev.b |= B_UP; + else if (gev.type & GPM_DRAG) ev.b |= B_DRAG; + else ev.b |= B_MOVE; + +#ifndef USE_GPM_DX + if (fb_msetsize < 0) { + } else if (fb_msetsize < 10) { + fb_msetsize++; + } else if ((ev.b & BM_ACT) == B_MOVE && !(ev.b & BM_BUTT)) { + fb_mouse_setsize(); + fb_msetsize = -1; + } +#endif + + if (((ev.b & BM_ACT) == B_MOVE && !(ev.b & BM_BUTT)) || (ev.b & BM_ACT) == B_DRAG) { + if (can_read(fb_hgpm)) goto again; + } + + if (!current_virtual_device) return; + if (current_virtual_device->mouse_handler) current_virtual_device->mouse_handler(current_virtual_device, ev.x, ev.y, ev.b); + redraw_mouse(); +} + +static int handle_fb_mouse(void) +{ + Gpm_Connect conn; +#ifndef USE_GPM_DX + int gpm_ver = 0; + struct winsize ws; + fb_old_ws_v = 0; +#endif + fb_hgpm = -1; +#ifndef USE_GPM_DX + Gpm_GetLibVersion(&gpm_ver); + fb_msetsize = -1; + if (gpm_ver >= 11900) { + int rs; + EINTRLOOP(rs,ioctl(1, TIOCGWINSZ, &ws)); + if (rs != -1) { + memcpy(&fb_old_ws, &ws, sizeof(struct winsize)); + fb_old_ws_v = 1; + ws.ws_row *= 2; + EINTRLOOP(rs, ioctl(1, TIOCSWINSZ, &ws)); + fb_msetsize = 0; + memcpy(&fb_new_ws, &ws, sizeof ws); + } + } + get_terminal_size(1, &fb_txt_xsize, &fb_txt_ysize); +#endif + conn.eventMask = ~0; + conn.defaultMask = gpm_smooth; + conn.minMod = 0; + conn.maxMod = -1; + if ((fb_hgpm = Gpm_Open(&conn, 0)) < 0) { + unhandle_fb_mouse(); + return -1; + } + set_handlers(fb_hgpm, fb_gpm_in, NULL, NULL, NULL); +#ifdef SIGTSTP + install_signal_handler(SIGTSTP, (void (*)(void *))sig_tstp, NULL, 0); +#endif +#ifdef SIGCONT + install_signal_handler(SIGCONT, (void (*)(void *))sig_cont, NULL, 0); +#endif +#ifdef SIGTTIN + install_signal_handler(SIGTTIN, (void (*)(void *))sig_tstp, NULL, 0); +#endif + + return 0; +} + +static void unhandle_fb_mouse(void) +{ + if (fb_hgpm >= 0) set_handlers(fb_hgpm, NULL, NULL, NULL, NULL); +#ifndef USE_GPM_DX + fb_hgpm = -1; + if (fb_old_ws_v) { + int rs; + EINTRLOOP(rs, ioctl(1, TIOCSWINSZ, &fb_old_ws)); + fb_old_ws_v = 0; + } +#endif + Gpm_Close(); +#ifdef SIGTSTP + install_signal_handler(SIGTSTP, (void (*)(void *))sig_tstp, NULL, 0); +#endif +#ifdef SIGCONT + install_signal_handler(SIGCONT, (void (*)(void *))sig_cont, NULL, 0); +#endif +#ifdef SIGTTIN + install_signal_handler(SIGTTIN, (void (*)(void *))sig_tstp, NULL, 0); +#endif +} + +#define seq_hide_cursor "\033[10000B\033[10000C\033[?25l" +#define seq_show_cursor "\033[10000D\033[?25h" + +static void fb_print(unsigned char *str) +{ + int wr; + EINTRLOOP(wr, write(TTY, str, strlen(str))); + if (wr <= 0) + EINTRLOOP(wr, write(1, str, strlen(str))); +} + +static void fb_hide_cursor(void) +{ + fb_print(seq_hide_cursor); +} + +static void fb_show_cursor(void) +{ + fb_print(seq_show_cursor); +} + +static unsigned char *fb_init_driver(unsigned char *param, unsigned char *ignore) +{ + unsigned char *e; + struct stat st; + int rs; + + TTY = 0; + EINTRLOOP(rs, ioctl(TTY,VT_GETMODE, &vt_omode)); + if (rs == -1) { + TTY = 1; + EINTRLOOP(rs, ioctl(TTY,VT_GETMODE, &vt_omode)); + if (rs == -1) { + TTY = 0; + } + } + + kbd_set_raw = 1; + fb_old_vd = NULL; + fb_driver_param=NULL; + if(param != NULL) + fb_driver_param=stracpy(param); + + border_left = border_right = border_top = border_bottom = 0; + if (!param) param=""; + if (*param) { + if (*param < '0' || *param > '9') + { bad_p: + if(fb_driver_param) { mem_free(fb_driver_param); fb_driver_param=NULL; } + return stracpy("-mode syntax is left_border[,top_border[,right_border[,bottom_border]]]\n"); } + border_left = strtoul(param, (char **)(void *)¶m, 10); + if ((unsigned long)border_left > MAXINT / 10) goto bad_p; + if (*param == ',') param++; + } else { + border_left = 0; + } + if (*param) { + if (*param < '0' || *param > '9') goto bad_p; + border_top = strtoul(param, (char **)(void *)¶m, 10); + if ((unsigned long)border_top > MAXINT / 10) goto bad_p; + if (*param == ',') param++; + } else { + border_top = border_left; + } + if (*param) { + if (*param < '0' || *param > '9') goto bad_p; + border_right = strtoul(param, (char **)(void *)¶m, 10); + if ((unsigned long)border_right > MAXINT / 10) goto bad_p; + if (*param == ',') param++; + } else { + border_right = border_left; + } + if (*param) { + if (*param < '0' || *param > '9') goto bad_p; + border_bottom = strtoul(param, (char **)(void *)¶m, 10); + if ((unsigned long)border_bottom > MAXINT / 10) goto bad_p; + if (*param == ',') param++; + } else { + border_bottom = border_top; + } + if (*param) goto bad_p; + + EINTRLOOP(rs, fstat(TTY, &st)); + if (rs) { + if(fb_driver_param) { mem_free(fb_driver_param); fb_driver_param=NULL; } + return stracpy("Cannon stat stdin.\n"); + } + + fb_console = st.st_rdev & 0xff; + + fb_hide_cursor(); + + if ((e = fb_switch_init())) { + if(fb_driver_param) { mem_free(fb_driver_param); fb_driver_param=NULL; } + fb_show_cursor(); + return e; + } + + EINTRLOOP(fb_handler, open("/dev/fb0", O_RDWR)); + if (fb_handler==-1) { + fb_switch_shutdown(); + if(fb_driver_param) { mem_free(fb_driver_param); fb_driver_param=NULL; } + fb_show_cursor(); + return stracpy("Cannot open /dev/fb0.\n"); + } + + EINTRLOOP(rs, ioctl (fb_handler, FBIOGET_VSCREENINFO, &vi)); + if (rs==-1) + { + EINTRLOOP(rs, close(fb_handler)); + fb_switch_shutdown(); + if(fb_driver_param) { mem_free(fb_driver_param); fb_driver_param=NULL; } + fb_show_cursor(); + return stracpy("Cannot get FB VSCREENINFO.\n"); + } + + oldmode=vi; + + EINTRLOOP(rs, ioctl (fb_handler, FBIOGET_FSCREENINFO, &fi)); + if (rs==-1) + { + EINTRLOOP(rs, close(fb_handler)); + fb_switch_shutdown(); + if(fb_driver_param) { mem_free(fb_driver_param); fb_driver_param=NULL; } + fb_show_cursor(); + return stracpy("Cannot get FB FSCREENINFO.\n"); + } + + fb_xsize=vi.xres; + fb_ysize=vi.yres; + fb_bits_pp=vi.bits_per_pixel; + if (fb_bits_pp == 16 && vi.green.length == 5) fb_bits_pp = 15; + + if (fb_xsize <= border_left + border_right) border_left = border_right = 0; + fb_xsize -= border_left + border_right; + if (fb_ysize <= border_top + border_bottom) border_top = border_bottom = 0; + fb_ysize -= border_top + border_bottom; + + fb_driver.x=fb_xsize; + fb_driver.y=fb_ysize; + + switch(fb_bits_pp) + { + case 4: + fb_pixelsize=1; + fb_palette_colors=16; + break; + + case 8: + fb_pixelsize=1; + fb_palette_colors=256; + break; + + case 15: + case 16: + fb_pixelsize=2; + fb_palette_colors=64; + break; + + case 24: + fb_palette_colors=256; + fb_pixelsize=3; + break; + + case 32: + fb_palette_colors=256; + fb_pixelsize=4; + fb_bits_pp=24; + break; + + default: + EINTRLOOP(rs, close(fb_handler)); + fb_switch_shutdown(); + if(fb_driver_param) { mem_free(fb_driver_param); fb_driver_param=NULL; } + fb_show_cursor(); + return stracpy("Unknown bit depth"); + } + fb_colors=1<<fb_bits_pp; + + if (fi.visual==FB_VISUAL_PSEUDOCOLOR && fb_colors <= 0x1000000) /* set palette */ + { + have_cmap=1; + fb_palette_colors=fb_colors; + alloc_palette(&old_palette); + get_palette(&old_palette); + + alloc_palette(&global_pal); + generate_palette(&global_pal); + set_palette(&global_pal); + } + if (fi.visual==FB_VISUAL_DIRECTCOLOR) /* set pseudo palette */ + { + have_cmap=2; + alloc_palette(&old_palette); + get_palette(&old_palette); + + alloc_palette(&global_pal); + generate_palette(&global_pal); + set_palette(&global_pal); + } + + fb_linesize=fi.line_length; + fb_mem_size=fi.smem_len; + + vi.xoffset=0; + vi.yoffset=0; + EINTRLOOP(rs, ioctl(fb_handler, FBIOPAN_DISPLAY, &vi)); + if (rs==-1) + { + /* mikulas : nechodilo mi to, tak jsem tohle vyhodil a ono to chodi */ + /*fb_shutdown_palette(); + EINTRLOOP(rs, close(fb_handler)); + fb_show_cursor(); + return stracpy("Cannot pan display.\n"); + */ + } + + if (init_virtual_devices(&fb_driver, NUMBER_OF_DEVICES)){ + fb_shutdown_palette(); + EINTRLOOP(rs, close(fb_handler)); + fb_switch_shutdown(); + if(fb_driver_param) { mem_free(fb_driver_param); fb_driver_param=NULL; } + fb_show_cursor(); + return stracpy("Allocation of virtual devices failed.\n"); + } + fb_kbd = handle_svgalib_keyboard((void (*)(void *, unsigned char *, int))fb_key_in); + + /* Mikulas: nechodi to na sparcu */ + if (fb_mem_size < (unsigned)((border_top + fb_ysize + border_bottom) * fb_linesize)) + { + fb_shutdown_palette(); + svgalib_free_trm(fb_kbd); + shutdown_virtual_devices(); + EINTRLOOP(rs, close(fb_handler)); + fb_switch_shutdown(); + if(fb_driver_param) { mem_free(fb_driver_param); fb_driver_param=NULL; } + fb_show_cursor(); + return stracpy("Nonlinear mapping of graphics memory not supported.\n"); + } + + if (vi.nonstd) { + fb_shutdown_palette(); + svgalib_free_trm(fb_kbd); + shutdown_virtual_devices(); + EINTRLOOP(rs, close(fb_handler)); + fb_switch_shutdown(); + if(fb_driver_param) { mem_free(fb_driver_param); fb_driver_param=NULL; } + fb_show_cursor(); + return stracpy("Non-standard pixel format.\n"); + } + + /* + * Some framebuffer implementations (for example Mach64) on Sparc64 hate + * partial framebuffer mappings. + * + * For others, we can save virtual memory space by doing a partial mmap. + */ + fb_mapped_size = (border_top + fb_ysize + border_bottom) * fb_linesize; +retry1: + if ((fb_mem=mmap(0,fb_mapped_size,PROT_READ|PROT_WRITE,MAP_SHARED,fb_handler,0))==MAP_FAILED) { + if (errno == EINTR) goto retry1; + fb_mapped_size = fb_mem_size; +retry2: + if ((fb_mem=mmap(0,fb_mapped_size,PROT_READ|PROT_WRITE,MAP_SHARED,fb_handler,0))==MAP_FAILED) { + if (errno == EINTR) goto retry2; + fb_shutdown_palette(); + svgalib_free_trm(fb_kbd); + shutdown_virtual_devices(); + + EINTRLOOP(rs, close(fb_handler)); + fb_switch_shutdown(); + if(fb_driver_param) { mem_free(fb_driver_param); fb_driver_param=NULL; } + fb_show_cursor(); + return stracpy("Cannot mmap graphics memory.\n"); + } + } + fb_vmem = fb_mem + border_left * fb_pixelsize + border_top * fb_linesize; + fb_driver.depth=fb_pixelsize&7; + fb_driver.depth|=(fb_bits_pp&31)<<3; + if (htonl(0x12345678) == 0x12345678) { + /* Big endian */ + if (fb_driver.depth == 130 || fb_driver.depth == 122) fb_driver.depth |= 1 << 8; + else if (fb_driver.depth == 196) fb_driver.depth |= 1 << 9; + } + + fb_driver.get_color=get_color_fn(fb_driver.depth); + if (!fb_driver.get_color) { + fb_shutdown_palette(); + svgalib_free_trm(fb_kbd); + shutdown_virtual_devices(); + + EINTRLOOP(rs, close(fb_handler)); + fb_switch_shutdown(); + if(fb_driver_param) { mem_free(fb_driver_param); fb_driver_param=NULL; } + fb_show_cursor(); + return stracpy("Unknown bit format.\n"); + } + /*fb_switch_init();*/ + install_signal_handler(SIGINT, (void (*)(void *))fb_ctrl_c, fb_kbd, 0); + + /* mouse */ + 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); + background_x=mouse_x=fb_xsize>>1; + background_y=mouse_y=fb_ysize>>1; + mouse_black=fb_driver.get_color(0); + mouse_white=fb_driver.get_color(0xffffff); + mouse_graphics_device=fb_driver.init_device(); + virtual_devices[0] = NULL; + global_mouse_hidden=1; + if (handle_fb_mouse()) { + fb_driver.shutdown_device(mouse_graphics_device); + mem_free(mouse_buffer); + mem_free(background_buffer); + mem_free(new_background_buffer); + fb_shutdown_palette(); + svgalib_free_trm(fb_kbd); + shutdown_virtual_devices(); + + EINTRLOOP(rs, close(fb_handler)); + fb_switch_shutdown(); + if(fb_driver_param) { mem_free(fb_driver_param); fb_driver_param=NULL; } + fb_show_cursor(); + return stracpy("Cannot open GPM mouse.\n"); + } + /* hide cursor */ + if (border_left | border_top | border_right | border_bottom) fb_clear_videoram(); + + show_mouse(); + return NULL; +} + +static void fb_shutdown_driver(void) +{ + int rs; + mem_free(mouse_buffer); + mem_free(background_buffer); + mem_free(new_background_buffer); + fb_driver.shutdown_device(mouse_graphics_device); + unhandle_fb_mouse(); + in_gr_operation++; + if (fb_active) { + fb_clear_videoram(); + EINTRLOOP(rs, ioctl (fb_handler, FBIOPUT_VSCREENINFO, &oldmode)); + } + END_GR; + fb_shutdown_palette(); + install_signal_handler(SIGINT, NULL, NULL, 0); + EINTRLOOP(rs, close(fb_handler)); + EINTRLOOP(rs, munmap(fb_mem,fb_mapped_size)); + shutdown_virtual_devices(); + fb_switch_shutdown(); + svgalib_free_trm(fb_kbd); + if(fb_driver_param) mem_free(fb_driver_param); + /* show cursor */ + fb_show_cursor(); +} + + +static unsigned char *fb_get_driver_param(void) +{ + return fb_driver_param; +} + + +/* Return value: 0 alloced on heap + * 1 alloced in vidram + * 2 alloced in X server shm + */ +static int fb_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; +} + +/* Return value: 0 alloced on heap + * 1 alloced in vidram + * 2 alloced in X server shm + */ +/* +static int fb_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; +} +*/ + +static void fb_register_bitmap(struct bitmap *bmp) +{ +} + +static void fb_unregister_bitmap(struct bitmap *bmp) +{ + mem_free(bmp->data); +} + +static void *fb_prepare_strip(struct bitmap *bmp, int top, int lines) +{ + return ((char *)bmp->data)+bmp->skip*top; +} + + +static void fb_commit_strip(struct bitmap *bmp, int top, int lines) +{ + return; +} + + +static void fb_draw_bitmap(struct graphics_device *dev,struct bitmap* hndl, int x, int y) +{ + unsigned char *scr_start; + int rs; + + CLIP_PREFACE + + scr_start=fb_vmem+y*fb_linesize+x*fb_pixelsize; + for(;ys;ys--){ + memcpy(scr_start,data,xs*fb_pixelsize); + data+=hndl->skip; + scr_start+=fb_linesize; + } + END_MOUSE + END_GR +} + + +#if 0 +static void fb_draw_bitmaps(struct graphics_device *dev, struct bitmap **hndls, int n, int x, int y) +{ + TEST_INACTIVITY + + if (x>=fb_xsize||y>fb_ysize) return; + while(x+(*hndls)->x<=0&&n){ + x+=(*hndls)->x; + n--; + hndls++; + } + while(n&&x<=fb_xsize){ + fb_draw_bitmap(dev, *hndls, x, y); + x+=(*hndls)->x; + n--; + hndls++; + } +} +#endif + + + +static void fb_fill_area(struct graphics_device *dev, int left, int top, int right, int bottom, long color) +{ + unsigned char *dest; + int y; + int rs; + + FILL_CLIP_PREFACE + + dest=fb_vmem+top*fb_linesize+left*fb_pixelsize; + for (y=bottom-top;y;y--){ + pixel_set(dest,(right-left)*fb_pixelsize,&color); + dest+=fb_linesize; + } + END_MOUSE + END_GR +} + + +static void fb_draw_hline(struct graphics_device *dev, int left, int y, int right, long color) +{ + unsigned char *dest; + int rs; + + HLINE_CLIP_PREFACE + + dest=fb_vmem+y*fb_linesize+left*fb_pixelsize; + pixel_set(dest,(right-left)*fb_pixelsize,&color); + END_MOUSE + END_GR +} + + +static void fb_draw_vline(struct graphics_device *dev, int x, int top, int bottom, long color) +{ + unsigned char *dest; + int y; + int rs; + + VLINE_CLIP_PREFACE + + dest=fb_vmem+top*fb_linesize+x*fb_pixelsize; + for (y=(bottom-top);y;y--){ + memcpy(dest,&color,fb_pixelsize); + dest+=fb_linesize; + } + END_MOUSE + END_GR +} + + +static int fb_hscroll(struct graphics_device *dev, struct rect_set **ignore, int sc) +{ + unsigned char *dest, *src; + int y; + int len; + int rs; + + HSCROLL_CLIP_PREFACE + + if (sc>0){ + len=(dev->clip.x2-dev->clip.x1-sc)*fb_pixelsize; + src=fb_vmem+fb_linesize*dev->clip.y1+dev->clip.x1*fb_pixelsize; + dest=src+sc*fb_pixelsize; + for (y=dev->clip.y2-dev->clip.y1;y;y--){ + memmove(dest,src,len); + dest+=fb_linesize; + src+=fb_linesize; + } + }else{ + len=(dev->clip.x2-dev->clip.x1+sc)*fb_pixelsize; + dest=fb_vmem+fb_linesize*dev->clip.y1+dev->clip.x1*fb_pixelsize; + src=dest-sc*fb_pixelsize; + for (y=dev->clip.y2-dev->clip.y1;y;y--){ + memmove(dest,src,len); + dest+=fb_linesize; + src+=fb_linesize; + } + } + END_MOUSE + END_GR + return 1; +} + + +static int fb_vscroll(struct graphics_device *dev, struct rect_set **ignore, int sc) +{ + unsigned char *dest, *src; + int y; + int len; + int rs; + + VSCROLL_CLIP_PREFACE + + len=(dev->clip.x2-dev->clip.x1)*fb_pixelsize; + if (sc>0){ + /* Down */ + dest=fb_vmem+(dev->clip.y2-1)*fb_linesize+dev->clip.x1*fb_pixelsize; + src=dest-fb_linesize*sc; + for (y=dev->clip.y2-dev->clip.y1-sc;y;y--){ + memcpy(dest,src,len); + dest-=fb_linesize; + src-=fb_linesize; + } + }else{ + /* Up */ + dest=fb_vmem+dev->clip.y1*fb_linesize+dev->clip.x1*fb_pixelsize; + src=dest-fb_linesize*sc; + for (y=dev->clip.y2-dev->clip.y1+sc;y;y--){ + memcpy(dest,src,len); + dest+=fb_linesize; + src+=fb_linesize; + } + } + END_MOUSE + END_GR + return 1; +} + + +static void fb_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>=fb_xsize + ||dev->clip.y1>=fb_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>fb_xsize) dev->clip.x2=fb_xsize; + if (dev->clip.y1<0) dev->clip.y1=0; + if (dev->clip.y2>fb_ysize) dev->clip.y2=fb_ysize; + } +} + +static int fb_block(struct graphics_device *dev) +{ + if (fb_old_vd) return 1; + fb_block_dev = dev; + unhandle_fb_mouse(); + fb_old_vd = current_virtual_device; + current_virtual_device=NULL; + svgalib_block_itrm(fb_kbd); + if (have_cmap) set_palette(&old_palette); + fb_switch_shutdown(); + fb_show_cursor(); + fb_print("\n"); + return 0; +} + +static int fb_unblock(struct graphics_device *dev) +{ + int rs; + if (current_virtual_device) { + return 0; + } + if (dev != fb_block_dev) return -2; + if (svgalib_unblock_itrm(fb_kbd)) return -1; + fb_switch_init(); + fb_hide_cursor(); + vi.xoffset=0; + vi.yoffset=0; + EINTRLOOP(rs, ioctl(fb_handler, FBIOPAN_DISPLAY, &vi)); + current_virtual_device = fb_old_vd; + fb_old_vd = NULL; + if (have_cmap) set_palette(&global_pal); + handle_fb_mouse(); + if (border_left | border_top | border_right | border_bottom) fb_clear_videoram(); + if (current_virtual_device) current_virtual_device->redraw_handler(current_virtual_device + ,¤t_virtual_device->size); + return 0; +} + + +struct graphics_driver fb_driver={ + "fb", + fb_init_driver, + init_virtual_device, + shutdown_virtual_device, + fb_shutdown_driver, + fb_get_driver_param, + fb_get_empty_bitmap, + /*fb_get_filled_bitmap,*/ + fb_register_bitmap, + fb_prepare_strip, + fb_commit_strip, + fb_unregister_bitmap, + fb_draw_bitmap, + /*fb_draw_bitmaps,*/ + NULL, /* fb_get_color */ + fb_fill_area, + fb_draw_hline, + fb_draw_vline, + fb_hscroll, + fb_vscroll, + fb_set_clip_area, + fb_block, + fb_unblock, + NULL, /* set_title */ + NULL, /* exec */ + NULL, /* set_clipboard_text */ + NULL, /* get_clipboard_text */ + 0, /* depth (filled in fb_init_driver function) */ + 0, 0, /* size (in X is empty) */ + GD_DONT_USE_SCROLL|GD_NEED_CODEPAGE, /* flags */ + 0, /* codepage */ + NULL, /* shell */ +}; + +#endif /* GRDRV_FB */ |