// TODO OPTIMIZE // #include "compositor.h" #include "scheduler.h" #include "syscalls.h" #include "kernel.h" #include "kmalloc.h" #include "log.h" #include "vmem.h" #include "timer.h" #include "asm_x86.h" #include "mount.h" #include "fd.h" #include "lib/string/string.h" #define MAX_WINDOWS 50 #define MAX_PID 200 #define MAX_ICONS 50 void load_bmp(uint8_t *dst,char *filename); static uint8_t backbuffer[VESA_MAX_WIDTH*VESA_MAX_HEIGHT*4]; static uint8_t wallpaper [VESA_MAX_WIDTH*VESA_MAX_HEIGHT*4]; static uint8_t icon_data [VESA_MAX_WIDTH*VESA_MAX_HEIGHT*4]; ringbuffer bg_invl; // TODO: int16 int32 mixed nonsense ! struct window { uint32_t pid; struct pdirectory *vmem; // retreive from task manager? uint8_t *fb; int16_t posx; int16_t posy; uint16_t width; uint16_t height; uint16_t active; bool draw_border; bool draw_meat; bool on_close; bool borderless; // never show borders bool fixed; // can not be moved }; struct icon { int16_t posx; int16_t posy; uint16_t active; uint32_t iconx; uint32_t icony; char command[64]; uint16_t width; uint16_t height; }; struct window windows[MAX_WINDOWS]; struct window *pid_to_win[MAX_PID]; struct icon icons[MAX_ICONS]; static uint16_t next_window=0; static uint16_t next_x=50; static uint16_t next_y=50; static uint16_t next_icon=0; static uint16_t next_icon_x; static uint16_t next_icon_y; static uint32_t *vmem=VMEM_FRAMEBUFFER; static uint16_t vesa_width; static uint16_t vesa_height; static uint16_t vesa_depth; static uint16_t vesa_pitch; // initial mouse state static int mouse_x=100; static int mouse_y=100; static int last_mouse_x; static int last_mouse_y; static uint16_t mouse_k=0; // icon static int mouse_icon_width=25; static int mouse_icon_height=25; static int mouse_icon_lx=0; static int mouse_icon_ly=0; static int mouse_icon_active_lx=0; static int mouse_icon_active_ly=25; static int X_icon_width=25; static int X_icon_height=25; static int X_icon_lx=0; static int X_icon_ly=50; static int X_icon_active_lx=0; static int X_icon_active_ly=75; // costly but beautiful static bool option_blending=false; // so better disable ! :P// also not allowed to read from vmem! :( // ugly and cheap static bool option_win_borders=true; // so enable static bool skip_render; static bool skip_render2; /** print single pixel to dst without bound checking */ static void put_pixel(uint8_t *dst, int x,int y, uint32_t color,uint16_t pitch,uint8_t depth,bool alpha) { uint8_t *p=dst+y*pitch+x*depth; *p++=color; *p++=color>>8; *p++=color>>16; if(alpha)*p=color>>24; } /** retrieves single pixel from src without bound checking */ static uint32_t get_pixel(uint8_t *src, int x,int y,uint16_t pitch,uint8_t depth,bool alpha) { uint32_t col=0; uint8_t *p=src+y*pitch+x*depth; col=(*p++); col+=(*p++)<<8; col+=(*p++)<<16; if(alpha)col+=(*p)<<24; return col; } /** print single pixel to dst without bound checking using alpha value, encoded alpha in the highest octet. 1-opaque 0-transparent no premultiplied alpha. TODO: change maybe for speedup!? **/ static void put_pixel_alpha(uint8_t *dst, int x,int y, uint32_t color,uint16_t pitch, uint8_t depth,bool alpha) { uint32_t col=get_pixel(dst,x,y,vesa_pitch,vesa_depth,false); uint8_t dst_b=col&0xff; uint8_t dst_g=(col&0xff00)>>8; uint8_t dst_r=(col&0xff0000)>>16; uint8_t src_b=color&0xff; uint8_t src_g=(color&0xff00)>>8; uint8_t src_r=(color&0xff0000)>>16; uint8_t src_a=(color&0xff000000)>>24; uint8_t out_r=((src_r*(src_a))>>8)+(((0xff-src_a)*dst_r)>>8); uint8_t out_g=((src_g*(src_a))>>8)+(((0xff-src_a)*dst_g)>>8); uint8_t out_b=((src_b*(src_a))>>8)+(((0xff-src_a)*dst_b)>>8); put_pixel(dst, x,y,(out_r<<16)+(out_g<<8)+out_b,vesa_pitch,vesa_depth,false); } // TODO fuck transparancey key. we have alfa now static void cpy_rect(uint8_t *src, uint16_t src_pitch, uint16_t src_x, uint16_t src_y, uint8_t *dst, uint16_t dst_pitch, uint16_t dst_x, uint16_t dst_y, uint16_t width, uint16_t height, bool bnd_chk, uint8_t mult, uint8_t div, bool transp, uint32_t transp_key, bool alpha) { // TODO optimize! for(int x=0;xactive) cpy_rect(icon_data,ico->iconx,ico->icony, // from dst, ico->posx,ico->posy, // to ico->width,ico->height, // icon dimensions false, 2, 0, // scaling not implemented yet anyway, not sure how to use them :P true, // transparency color key 0xff00ff // color key of transp ,false ); else cpy_rect(icon_data,ico->iconx,ico->icony, // from dst, ico->posx,ico->posy, // to ico->width,ico->height, // icon dimensions false, 0, 0, // scaling not implemented yet anyway, not sure how to use them :P true, // transparency color key 0xff00ff // color key of transp ,true ); } */ static void put_win(uint8_t *dst, struct window *win) { struct pdirectory* mydir; x86_cli();// do not reschedule us til ready! mydir=x86_get_page_directory(); x86_set_page_directory(win->vmem); cpy_rect(win->fb,win->width*4,0,0, // from dst,vesa_pitch,win->posx,win->posy, // to win->width,win->height, // icon dimensions false, 0, 0, // scaling not implemented yet anyway, not sure how to use them :P true, // transparency color key 0xff00ff // color key of transp ,true ); int iconx=X_icon_lx; int icony=X_icon_ly; if(win->on_close) { iconx=X_icon_active_lx; icony=X_icon_active_ly; } cpy_rect(icon_data,vesa_pitch,iconx,icony, // from dst, vesa_pitch,win->posx+win->width-X_icon_width,win->posy, // to X_icon_width,X_icon_height, // icon dimensions false, 0, 0, // scaling not implemented yet anyway, not sure how to use them :P true, // transparency color key 0xff00ff // color key of transp ,true ); // iterate over invalidated rects //// while(ringbuffer_has(win->invl)) //// { //// int ry=ringbuffer_get(win->invl)+256*ringbuffer_get(win->invl); //// int rx=ringbuffer_get(win->invl)+256*ringbuffer_get(win->invl); //// int rh=ringbuffer_get(win->invl)+256*ringbuffer_get(win->invl); //// int rw=ringbuffer_get(win->invl)+256*ringbuffer_get(win->invl); //// if(!win->draw_meat)continue; //// //// uint32_t userx=rx; //// uint32_t usery=ry; //// //// // iterate over rect area //// for(uint16_t x=win->posx+rx;xposx+rx+rw;x++) //// { //// usery=ry; //// for(uint16_t y=win->posy+ry;yposy+ry+rh;y++) //// { //// // blending non-active windows (TODO: costly?) //// if(!win->active && option_blending) //// { //// /* //// uint8_t dst_b=backbuffer[y*vesa_width+x]&0xff; //// uint8_t dst_g=(backbuffer[y*vesa_width+x]&0xff00)>>8; //// uint8_t dst_r=(backbuffer[y*vesa_width+x]&0xff0000)>>16; //// //// uint16_t a; //// //// uint32_t col=0xff0000; //// col=user_vmem[userx+usery*640]; //// uint8_t src_b=col&0xff; //// uint8_t src_g=(col&0xff00)>>8; //// uint8_t src_r=(col&0xff0000)>>16; //// a=0x44; //// //// //// uint8_t out_r=((src_r*(0xff-a))>>8)+((a*dst_r)>>8); //// uint8_t out_g=((src_g*(0xff-a))>>8)+((a*dst_g)>>8); //// uint8_t out_b=((src_b*(0xff-a))>>8)+((a*dst_b)>>8); //// //// backbuffer[y*vesa_width+x]=(out_r<<16)+(out_g<<8)+out_b; //// */ //// //// put_pixel_alpha(dst,x,y,(user_vmem[userx+usery*640])); //// } //// else //// { //// put_pixel(dst,x,y,(user_vmem[userx+usery*640])); //// } //// //// usery++; //// } //// userx++; //// } //// } //if(win->vmem) //{ x86_set_page_directory(mydir); x86_sti(); //} //draw boundaries if(option_win_borders&&win->draw_border) { uint32_t border_col=0x002b36; if(win->active)border_col=0xfdfd6e3; //TODO win->draw_border=false; for(uint16_t x=win->posx;xposx+win->width;x++) { put_pixel(dst,x,win->posy,border_col,vesa_pitch,vesa_depth,false); //TOP put_pixel(dst,x,win->posy+win->height-1,border_col,vesa_pitch,vesa_depth,false); //BOTTOM } for(uint16_t y=win->posy;yposy+win->height;y++) { put_pixel(dst,win->posx,y,border_col,vesa_pitch,vesa_depth,false); //LEFT put_pixel(dst,win->posx+win->width-1,y,border_col,vesa_pitch,vesa_depth,false); //RIGHT } } // } static void put_bg(uint8_t *dst) { cpy_rect(wallpaper,vesa_pitch,0,0 , // from dst,vesa_pitch,0,0, // to vesa_width,vesa_height, // icon dimensions false, 0, 0, // scaling not implemented yet anyway, not sure how to use them :P false, // transparency color key 0xffffff // color key of transp ,false ); } static void put_mouse(uint8_t *dst) { static int last_put_mouse_x=0; static int last_put_mouse_y=0; int iconx=mouse_icon_lx; int icony=mouse_icon_ly; if(mouse_k&1) { iconx=mouse_icon_active_lx; icony=mouse_icon_active_ly; } last_put_mouse_x=mouse_x; last_put_mouse_y=mouse_y; cpy_rect(icon_data,vesa_pitch,iconx,icony, // from dst, vesa_pitch,mouse_x,mouse_y, // to mouse_icon_width,mouse_icon_height, // icon dimensions false, 0, 0, // scaling not implemented yet anyway, not sure how to use them :P true, // transparency color key 0xff00ff // color key of transp ,true ); } void compositor_del_window(uint32_t addr) { for(int i=0;i3000) { klog("fps: %d",frames*1000/(now-last)); last=now; frames=0; } // // // put_bg(backbuffer); for(int i=next_window-1;i>=0;i--) { put_win(backbuffer,&windows[i]); } put_mouse(backbuffer); memcpy(VMEM_FRAMEBUFFER,backbuffer,vesa_pitch*vesa_height); } void compositor_kb_handle(char c) { for(int i=0;iactive) { // klog("writing [%c] to window with pid [%d]",c,w->pid); fd_write(get_tty(w->pid),c); } } } // TODO: check what is active ONLY on refresh screen! void compositor_mouse_handle(int16_t diff_x,int16_t diff_y, uint8_t key) { // klog("%d %d %d",diff_x,diff_y,key); static uint8_t lastkey=0; if(!(key&2)&&(lastkey&2)) // right mouse click { lastkey=key; klog("tell init to spawn new foolshell"); fd_write(get_tty(1),'0'); // tell init to spawn new xterm } mouse_x+=diff_x; mouse_y+=diff_y; mouse_k=key; if(mouse_x<0)mouse_x=0; if(mouse_y<0)mouse_y=0; if(mouse_x>=vesa_width-mouse_icon_width)mouse_x=vesa_width-1-mouse_icon_width; if(mouse_y>=vesa_height-mouse_icon_height)mouse_y=vesa_height-1-mouse_icon_height; if(!(key&1)) { last_mouse_x=mouse_x; last_mouse_y=mouse_y; } int active=-1; bool active_win=false; for(int i=0;iw->posx&&mouse_xposx+w->width&&mouse_y>w->posy&&mouse_yposy+w->height) { if(key&1) { /* w->posx-=last_mouse_x-mouse_x; last_mouse_x=mouse_x; w->posy-=last_mouse_y-mouse_y; last_mouse_y=mouse_y; if(w->posx<0)w->posx=0; if(w->posy<0)w->posy=0; if(w->posx+w->width>=vesa_width)w->posx=vesa_width-640; if(w->posy+w->height>=vesa_height)w->posy=vesa_height-480; */ } w->active=true; active=i; } else { w->active=false; } } for(int i=0;ion_close=false; if(active==-1&&mouse_x>w->posx&&mouse_xposx+w->width&&mouse_y>w->posy&&mouse_yposy+w->height) { if(key&1) { w->draw_meat=false; uint32_t xy=(w->posx<<16)|(w->posy); uint32_t wh=(640<<16)|(400); /* ringbuffer_put(&bg_invl,xy&0x000000ff); ringbuffer_put(&bg_invl,(xy&0x0000ff00)>>8); ringbuffer_put(&bg_invl,(xy&0x00ff0000)>>16); ringbuffer_put(&bg_invl,(xy&0xff000000)>>24); ringbuffer_put(&bg_invl,wh&0x000000ff); ringbuffer_put(&bg_invl,(wh&0x0000ff00)>>8); ringbuffer_put(&bg_invl,(wh&0x00ff0000)>>16); ringbuffer_put(&bg_invl,(wh&0xff000000)>>24); */ w->posx-=last_mouse_x-mouse_x; last_mouse_x=mouse_x; w->posy-=last_mouse_y-mouse_y; last_mouse_y=mouse_y; if(w->posx<0)w->posx=0; if(w->posy<0)w->posy=0; if(w->posx+w->width>=vesa_width)w->posx=vesa_width-640; if(w->posy+w->height>=vesa_height)w->posy=vesa_height-400; w->draw_border=true; } else { w->draw_meat=true; if(lastkey&1) { w->draw_border=true; uint32_t xy=(0<<16)|(0); uint32_t wh=(640<<16)|(400); /// ringbuffer_put(w->invl,xy&0x000000ff); /// ringbuffer_put(w->invl,(xy&0x0000ff00)>>8); /// ringbuffer_put(w->invl,(xy&0x00ff0000)>>16); /// ringbuffer_put(w->invl,(xy&0xff000000)>>24); /// /// ringbuffer_put(w->invl,wh&0x000000ff); /// ringbuffer_put(w->invl,(wh&0x0000ff00)>>8); /// ringbuffer_put(w->invl,(wh&0x00ff0000)>>16); /// ringbuffer_put(w->invl,(wh&0xff000000)>>24); } } w->active=true; active_win=true; active=i; if(mouse_x>w->posx+w->width-X_icon_width&&mouse_yposy+X_icon_height)w->on_close=true; } else { w->active=false; } } if(active_win&&active!=-1&&active!=0&&(key&1)) { struct window temp; temp=windows[active]; windows[active]=windows[0]; pid_to_win[windows[0].pid]=&windows[active]; windows[0]=temp; pid_to_win[windows[0].pid]=&windows[0]; } lastkey=key; } /** THIS CAN LOAD WINDOWS ARGB BITMAPS WITH BITMAPINFOHEADER */ void load_bmp(uint8_t *dst,char *filename) { klog("loading bitmap %s",filename); fd dat=mount_file_open(filename); char B=fd_read(&dat); // 0x0 char M=fd_read(&dat); // 0x1 //klog("id = %c%c",M,B); if(M!='M'||B!='B')kpanic("not a (windows) bitmap!"); uint32_t size=(fd_read(&dat))+(fd_read(&dat)<<8)+(fd_read(&dat)<<16)+(fd_read(&dat)<<24); //0x02 klog("bytes = 0x%08x",size); // skip next 4 reserved bytes fd_read(&dat); fd_read(&dat); fd_read(&dat); fd_read(&dat); uint32_t off=(fd_read(&dat))+(fd_read(&dat)<<8)+(fd_read(&dat)<<16)+(fd_read(&dat)<<24); //0x0a klog("offset = 0x%08X",off); // skip next 4 bytes fd_read(&dat); fd_read(&dat); fd_read(&dat); fd_read(&dat); uint32_t w=(fd_read(&dat))+(fd_read(&dat)<<8)+(fd_read(&dat)<<16)+(fd_read(&dat)<<24); //0x12 uint32_t h=(fd_read(&dat))+(fd_read(&dat)<<8)+(fd_read(&dat)<<16)+(fd_read(&dat)<<24); //0x16 klog("width=%d,height=%d",w,h); for(int i=0;i=vesa_width)continue; if(h-y-1>=vesa_height)continue; put_pixel(dst,x,h-y-1,val,vesa_pitch,4,true); } } } void compositor_invalidate(uint32_t pid,uint16_t x, uint16_t y, uint16_t w, uint16_t h,uint32_t *fb) { if(fb!=0)pid_to_win[pid]->fb=fb; // klog("pid %d invalidating %dx%d rect at %d %d with fb addr 0x%08x",pid,w,h,x,y,fb); } int compositor_create_window(uint32_t pid,uint16_t x, uint16_t y,uint16_t w,uint16_t h,uint16_t flags) { klog("pid %d creating %dx%d win at %d %d with flags 0x%02x",pid,w,h,x,y,flags); if (next_window>=MAX_WINDOWS)kpanic("max number of windows reached. increase MAX_WINDOWS"); windows[next_window]=windows[0]; pid_to_win[windows[0].pid]=&windows[next_window]; // auto position if(x==0xffff) { next_x+=100; next_y+=100; windows[0].posx=next_x; windows[0].posy=next_y; } else { windows[0].posx=x; windows[0].posy=y; } windows[0].width=w; windows[0].height=h; windows[0].active=0; windows[0].fb=0; windows[0].vmem=scheduler_get_vmem(pid); windows[0].pid=pid; windows[0].draw_border=true; windows[0].draw_meat=true; windows[0].on_close=false; windows[0].borderless=flags&1; windows[0].fixed=flags&2; pid_to_win[windows[0].pid]=&windows[0]; next_window++; compositor_mouse_handle(0,0,0); return 0;// ok } void compositor_destroy_window(uint32_t pid) { klog("destroying win for pid %d",pid); }