📄 framebuffer.c
字号:
/* 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#ifdef TEXT#undef TEXT#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 <signal.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#define TTY 0#ifndef USE_GPM_DXint fb_txt_xsize, fb_txt_ysize;struct winsize fb_old_ws;struct winsize fb_new_ws;int fb_old_ws_v;int fb_msetsize;#endifint fb_hgpm;int fb_console;struct itrm *fb_kbd;struct graphics_device *fb_old_vd;struct graphics_device *fb_block_dev;int fb_handler;char *fb_mem, *fb_vmem;int fb_mem_size,fb_linesize,fb_bits_pp,fb_pixelsize;int fb_xsize,fb_ysize;int border_left, border_right, border_top, border_bottom;int fb_colors, fb_palette_colors;struct fb_var_screeninfo vi;struct fb_fix_screeninfo fi;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;int have_cmap=0;volatile int fb_active=1;struct palette{ unsigned short *red; unsigned short *green; unsigned short *blue;};struct palette old_palette;struct palette global_pal;static struct vt_mode vt_mode,vt_omode;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 START_GR \ in_gr_operation=1; \ if (!fb_active) { in_gr_operation=0; ioctl(TTY,VT_RELDISP,1); return; }#define START_GR_0 \ in_gr_operation=1; \ if (!fb_active) { in_gr_operation=0; ioctl(TTY,VT_RELDISP,1); return 0; }#define END_GR \ in_gr_operation=0;\ if (!fb_active)ioctl(TTY,VT_RELDISP,1); #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;\ 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)\ /* n is in bytes. dest must begin on pixel boundary. */static inline void pixel_set(unsigned char *dest, int n,void * pattern){ int a; switch(fb_pixelsize) { case 1: memset(dest,*(char *)pattern,n); break; case 2: {#ifdef t2c t2c v=*(t2c *)pattern; int a; if ((v & 255) == ((v >> 8) & 255)) memset(dest, v, n); else for (a=0;a<(n>>1);a++) ((t2c *)dest)[a]=v;#else unsigned char a,b; int i; a=*(char*)pattern; b=((char*)pattern)[1]; if (a == b) memset(dest, a, n); else for (i=0;i<=n-2;i+=2){ dest[i]=a; dest[i+1]=b; }#endif } break; case 3: { unsigned char a,b,c; int i; a=*(char*)pattern; b=((char*)pattern)[1]; c=((char*)pattern)[2]; if (a == b && b == c) memset(dest, a, n); else for (i=0;i<=n-3;i+=3){ dest[i]=a; dest[i+1]=b; dest[i+2]=c; } } break; case 4: {#ifdef t4c t4c v=*(t4c *)pattern; int a; for (a=0;a<(n>>2);a++) ((t4c *)dest)[a]=v;#else unsigned char a,b,c,d; int i; a=*(char*)pattern; b=((char*)pattern)[1]; c=((char*)pattern)[2]; d=((char*)pattern)[3]; for (i=0;i<=n-4;i+=4){ dest[i]=a; dest[i+1]=b; dest[i+2]=c; dest[i+3]=d; }#endif } break; default: for (a=0;a<n/fb_pixelsize;a++,dest+=fb_pixelsize) memcpy(dest,pattern,fb_pixelsize); break; }}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) || 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; int *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{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -