diff --git a/src/conio/bitmap_con.c b/src/conio/bitmap_con.c index 1cd56f3e15f59bc022a306ed5170f6dbf91775a4..da0b2dc466bad858fa6e9d010d9b2f82edf5c19e 100644 --- a/src/conio/bitmap_con.c +++ b/src/conio/bitmap_con.c @@ -31,6 +31,7 @@ int screenheight; #define PIXEL_OFFSET(x,y) ( (y)*screenwidth+(x) ) static int current_font=-99; +static int bitmap_initialized=0; struct video_stats vstat; struct bitmap_callbacks { @@ -78,9 +79,14 @@ static void blinker_thread(void *data) } } +/* + * MUST be called only once and before any other bitmap functions + */ int bitmap_init(void (*drawrect_cb) (int xpos, int ypos, int width, int height, unsigned char *data) ,void (*flush_cb) (void)) { + if(bitmap_initialized) + return(-1); pthread_mutex_init(&vstatlock, NULL); pthread_mutex_init(&screenlock, NULL); pthread_mutex_lock(&vstatlock); @@ -89,49 +95,26 @@ int bitmap_init(void (*drawrect_cb) (int xpos, int ypos, int width, int height, callbacks.drawrect=drawrect_cb; callbacks.flush=flush_cb; + bitmap_initialized=1; _beginthread(blinker_thread,0,NULL); return(0); } -void send_rectangle(int xoffset, int yoffset, int width, int height, int force) -{ - unsigned char *rect; - int pixel=0; - int inpixel; - int x,y; - - pthread_mutex_lock(&screenlock); - if(callbacks.drawrect) { -#ifdef PARANOIA - if(xoffset < 0 || xoffset >= screenwidth || yoffset < 0 || yoffset >= screenheight || width <= 0 || width > screenwidth || height <=0 || height >screenheight) { - pthread_mutex_unlock(&screenlock); - return; - } -#endif - - rect=(unsigned char *)malloc(width*height*sizeof(unsigned char)); - if(!rect) { - pthread_mutex_unlock(&screenlock); - return; - } - - for(y=0; y<height; y++) { - inpixel=PIXEL_OFFSET(xoffset, yoffset+y); - for(x=0; x<width; x++) { - rect[pixel++]=vstat.palette[screen[inpixel++]]; - } - } - callbacks.drawrect(xoffset,yoffset,width,height,rect); - } - pthread_mutex_unlock(&screenlock); -} - +/* + * This function is intended to be called from the driver. + * as a result, it cannot block waiting for driver status + * + * Care MUST be taken to avoid deadlocks... + */ int bitmap_init_mode(int mode, int *width, int *height) { int i; char *newscreen; + if(!bitmap_initialized) + return(-1); + pthread_mutex_lock(&vstatlock); if(load_vmode(&vstat, mode)) { @@ -177,6 +160,40 @@ int bitmap_init_mode(int mode, int *width, int *height) return(0); } +/* + * Send by ciolib side, should not block in driver + * Generally, if the driver may block on a rectangle draw, the updates + * should be cached until flush is called. + */ +void send_rectangle(int xoffset, int yoffset, int width, int height, int force) +{ + unsigned char *rect; + int pixel=0; + int inpixel; + int x,y; + + if(!bitmap_initialized) + return; + pthread_mutex_lock(&screenlock); + if(callbacks.drawrect) { + if(xoffset < 0 || xoffset >= screenwidth || yoffset < 0 || yoffset >= screenheight || width <= 0 || width > screenwidth || height <=0 || height >screenheight) + goto end; + + rect=(unsigned char *)malloc(width*height*sizeof(unsigned char)); + if(!rect) + goto end; + + for(y=0; y<height; y++) { + inpixel=PIXEL_OFFSET(xoffset, yoffset+y); + for(x=0; x<width; x++) + rect[pixel++]=vstat.palette[screen[inpixel++]]; + } + callbacks.drawrect(xoffset,yoffset,width,height,rect); + } +end: + pthread_mutex_unlock(&screenlock); +} + /********************************************************/ /* High Level Stuff */ /********************************************************/ @@ -188,7 +205,8 @@ int bitmap_puttext(int sx, int sy, int ex, int ey, void *fill) unsigned char *out; WORD sch; - pthread_mutex_lock(&vstatlock); + if(!bitmap_initialized) + return(0); if( sx < 1 || sy < 1 || ex < 1 @@ -199,11 +217,10 @@ int bitmap_puttext(int sx, int sy, int ex, int ey, void *fill) || sy > ey || ex > cio_textinfo.screenwidth || ey > cio_textinfo.screenheight - || fill==NULL) { - pthread_mutex_unlock(&vstatlock); + || fill==NULL) return(0); - } + pthread_mutex_lock(&vstatlock); out=fill; for(y=sy-1;y<ey;y++) { for(x=sx-1;x<ex;x++) { @@ -223,7 +240,8 @@ int bitmap_gettext(int sx, int sy, int ex, int ey, void *fill) unsigned char *out; WORD sch; - pthread_mutex_lock(&vstatlock); + if(!bitmap_initialized) + return(0); if( sx < 1 || sy < 1 @@ -233,11 +251,10 @@ int bitmap_gettext(int sx, int sy, int ex, int ey, void *fill) || sy > ey || ex > cio_textinfo.screenwidth || ey > cio_textinfo.screenheight - || fill==NULL) { - pthread_mutex_unlock(&vstatlock); + || fill==NULL) return(0); - } + pthread_mutex_lock(&vstatlock); out=fill; for(y=sy-1;y<ey;y++) { for(x=sx-1;x<ex;x++) { @@ -250,9 +267,11 @@ int bitmap_gettext(int sx, int sy, int ex, int ey, void *fill) return(1); } -/* Called from main thread only */ +/* Called from ciolib thread only */ void bitmap_setcursortype(int type) { + if(!bitmap_initialized) + return; pthread_mutex_lock(&vstatlock); switch(type) { case _NOCURSOR: @@ -268,7 +287,6 @@ void bitmap_setcursortype(int type) vstat.curs_end = vstat.default_curs_end; break; } - update_rect(cio_textinfo.curx+cio_textinfo.winleft-1,cio_textinfo.cury+cio_textinfo.wintop-1,1,1,TRUE,TRUE); pthread_mutex_unlock(&vstatlock); } @@ -285,6 +303,8 @@ int bitmap_setfont(int font, int force) char *pold; char *pnew; + if(!bitmap_initialized) + return(-1); if(font < 0 || font>(sizeof(conio_fontdata)/sizeof(struct conio_font_data_struct)-2)) return(-1); @@ -295,11 +315,12 @@ int bitmap_setfont(int font, int force) else if(conio_fontdata[font].eight_by_eight!=NULL) newmode=C80X50; + pthread_mutex_lock(&vstatlock); switch(vstat.charheight) { case 8: if(conio_fontdata[font].eight_by_eight==NULL) { if(force) - return(-1); + goto error_return; else changemode=1; } @@ -307,7 +328,7 @@ int bitmap_setfont(int font, int force) case 14: if(conio_fontdata[font].eight_by_fourteen==NULL) { if(force) - return(-1); + goto error_return; else changemode=1; } @@ -315,18 +336,20 @@ int bitmap_setfont(int font, int force) case 16: if(conio_fontdata[font].eight_by_sixteen==NULL) { if(force) - return(-1); + goto error_return; else changemode=1; } break; } if(changemode && newmode==-1) - return(-1); + goto error_return; current_font=font; + pthread_mutex_unlock(&vstatlock); + if(changemode) { gettextinfo(&ti); - + attr=ti.attribute; ow=ti.screenwidth; oh=ti.screenheight; @@ -369,6 +392,10 @@ int bitmap_setfont(int font, int force) } bitmap_loadfont(NULL); return(0); + +error_return: + pthread_mutex_unlock(&vstatlock); + return(-1); } int bitmap_getfont(void) @@ -384,8 +411,10 @@ int bitmap_loadfont(char *filename) int fw; int fh; int i; - FILE *fontfile; + FILE *fontfile=NULL; + if(!bitmap_initialized) + return(-1); if(current_font==-99 || current_font>(sizeof(conio_fontdata)/sizeof(struct conio_font_data_struct)-2)) { for(i=0; conio_fontdata[i].desc != NULL; i++) { if(!strcmp(conio_fontdata[i].desc, "Codepage 437 English")) { @@ -408,30 +437,19 @@ int bitmap_loadfont(char *filename) fontsize=fw*fh*256*sizeof(unsigned char); if(font) - free(font); - if((font=(unsigned char *)malloc(fontsize))==NULL) { - pthread_mutex_unlock(&vstatlock); - return(-1); - } + FREE_AND_NULL(font); + if((font=(unsigned char *)malloc(fontsize))==NULL) + goto error_return; if(filename != NULL) { - if(flength(filename)!=fontsize) { - pthread_mutex_unlock(&vstatlock); - free(font); - return(-1); - } - if((fontfile=fopen(filename,"rb"))==NULL) { - pthread_mutex_unlock(&vstatlock); - free(font); - return(-1); - } - if(fread(font, 1, fontsize, fontfile)!=fontsize) { - pthread_mutex_unlock(&vstatlock); - free(font); - fclose(fontfile); - return(-1); - } + if(flength(filename)!=fontsize) + goto error_return; + if((fontfile=fopen(filename,"rb"))==NULL) + goto error_return; + if(fread(font, 1, fontsize, fontfile)!=fontsize) + goto error_return; fclose(fontfile); + fontfile=NULL; current_font=-1; if(filename != current_filename) SAFECOPY(current_filename,filename); @@ -441,48 +459,42 @@ int bitmap_loadfont(char *filename) case 8: switch(vstat.charheight) { case 8: - if(conio_fontdata[current_font].eight_by_eight==NULL) { - pthread_mutex_unlock(&vstatlock); - free(font); - return(-1); - } + if(conio_fontdata[current_font].eight_by_eight==NULL) + goto error_return; memcpy(font, conio_fontdata[current_font].eight_by_eight, fontsize); break; case 14: - if(conio_fontdata[current_font].eight_by_fourteen==NULL) { - pthread_mutex_unlock(&vstatlock); - free(font); - return(-1); - } + if(conio_fontdata[current_font].eight_by_fourteen==NULL) + goto error_return; memcpy(font, conio_fontdata[current_font].eight_by_fourteen, fontsize); break; case 16: - if(conio_fontdata[current_font].eight_by_sixteen==NULL) { - pthread_mutex_unlock(&vstatlock); - free(font); - return(-1); - } + if(conio_fontdata[current_font].eight_by_sixteen==NULL) + goto error_return; memcpy(font, conio_fontdata[current_font].eight_by_sixteen, fontsize); break; default: - pthread_mutex_unlock(&vstatlock); - free(font); - return(-1); + goto error_return; } break; default: - pthread_mutex_unlock(&vstatlock); - free(font); - return(-1); + goto error_return; } } force_redraws++; pthread_mutex_unlock(&vstatlock); return(0); + +error_return: + FREE_AND_NULL(font); + if(fontfile) + fclose(fontfile); + pthread_mutex_unlock(&vstatlock); + return(-1); } -/* Called from events thread only */ +/* vstatlock is held */ static void bitmap_draw_cursor(int flush) { int x; @@ -493,6 +505,8 @@ static void bitmap_draw_cursor(int flush) int start,end; int width; + if(!bitmap_initialized) + return; if(vstat.blink && !hold_update) { if(vstat.curs_start<=vstat.curs_end) { xoffset=(cio_textinfo.curx+cio_textinfo.winleft-2)*vstat.charwidth; @@ -521,6 +535,8 @@ void bitmap_gotoxy(int x, int y) { static int lx=-1,ly=-1; + if(!bitmap_initialized) + return; pthread_mutex_lock(&vstatlock); if((x != cio_textinfo.curx) || (y != cio_textinfo.cury)) { vstat.curs_col=x+cio_textinfo.winleft-1; @@ -530,16 +546,17 @@ void bitmap_gotoxy(int x, int y) } if(!hold_update) { /* Erase old cursor */ - if(lx != vstat.curs_col || ly != vstat.curs_row) - update_rect(lx,ly,1,1,TRUE,TRUE); +// if(lx != vstat.curs_col || ly != vstat.curs_row) +// update_rect(lx,ly,1,1,TRUE,TRUE); /* Draw new cursor */ - bitmap_draw_cursor(TRUE); +// bitmap_draw_cursor(TRUE); lx=vstat.curs_col; ly=vstat.curs_row; } pthread_mutex_unlock(&vstatlock); } +/* vstatlock is held */ static int bitmap_draw_one_char(unsigned int xpos, unsigned int ypos) { int fg; @@ -551,6 +568,9 @@ static int bitmap_draw_one_char(unsigned int xpos, unsigned int ypos) int fontoffset; WORD sch; + if(!bitmap_initialized) + return(-1); + if(!screen) return(-1); @@ -583,6 +603,7 @@ static int bitmap_draw_one_char(unsigned int xpos, unsigned int ypos) return(0); } +/* vstatlock is held */ static int update_rect(int sx, int sy, int width, int height, int force, int calls_send) { int x,y; @@ -597,6 +618,9 @@ static int update_rect(int sx, int sy, int width, int height, int force, int cal struct rectangle last_rect; int last_rect_used=0; + if(!bitmap_initialized) + return(-1); + if(sx==0 && sy==0 && width==0 && height==0) fullredraw=1; @@ -629,7 +653,9 @@ static int update_rect(int sx, int sy, int width, int height, int force, int cal /* Redraw all chars */ if(vstat.blink != vs.blink || vstat.curs_col!=vs.curs_col - || vstat.curs_row!=vs.curs_row) + || vstat.curs_row!=vs.curs_row + || vstat.curs_start!=vs.curs_start + || vstat.curs_end!=vs.curs_end) redraw_cursor=1; for(y=0;y<height;y++) { @@ -718,10 +744,13 @@ static int update_rect(int sx, int sy, int width, int height, int force, int cal } } - /* Did we redraw the cursor? If so, update position */ + /* Did we redraw the cursor? If so, update cursor info */ if(redraw_cursor) { vs.curs_col=vstat.curs_col; vs.curs_row=vstat.curs_row; + vs.blink=vstat.blink; + vs.curs_start=vstat.curs_start; + vs.curs_end=vstat.curs_end; } /* On full redraws, save the last blink value */