⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 framebuffer.c

📁 ELinks is an advanced and well-established feature-rich text mode web (HTTP/FTP/..) browser. ELinks
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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 + -