#include "compositor.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_ICONS 50 ringbuffer bg_invl; // TODO: int16 int32 mixed nonsense // struct window { uint32_t pid; ringbuffer *invl; struct pdirectory *vmem; // retreive from task manager? int16_t posx; int16_t posy; uint16_t width; uint16_t height; uint16_t active; bool draw_border; bool draw_meat; }; 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 icon icons[MAX_ICONS]; static uint8_t backbuffer [VESA_MAX_WIDTH*VESA_MAX_HEIGHT*4]; static uint8_t bgimage [VESA_MAX_WIDTH*VESA_MAX_HEIGHT*4]; static uint8_t icon_data [1920*1080*4]; 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; // 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) { uint8_t *p=dst+y*vesa_pitch+x*vesa_depth; *p++=color; // waste for 24bit... *p++=color>>8; // waste for 24bit... *p=color>>16; // waste for 24bit... } /** retrieves single pixel from src without bound checking */ static uint32_t get_pixel(uint8_t *src, int x,int y) { uint32_t col=0; uint8_t *p=src+y*vesa_pitch+x*vesa_depth; col=(*p++); // waste for 24bit... col+=(*p++)<<8; // waste for 24bit... col+=(*p)<<16; // waste for 24bit... 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) { // TODO: do not use hardcoded alpha! uint16_t a=0xaa; uint32_t col=get_pixel(dst,x,y); // TODO: optimize!! 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 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); put_pixel(dst, x,y,(out_r<<16)+(out_g<<8)+out_b); } static void cpy_rect(uint8_t *src, uint16_t src_x, uint16_t src_y, uint8_t *dst, 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); uint32_t *user_vmem=VMEM_USER_FRAMEBUFFER; // 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) { win->draw_border=false; for(uint16_t x=win->posx;xposx+win->width;x++) { put_pixel(dst,x,win->posy,0xffffff); //TOP put_pixel(dst,x,win->posy+win->height-1,0xffffff); //BOTTOM } for(uint16_t y=win->posy;yposy+win->height;y++) { put_pixel(dst,win->posx,y,0xffffff); //LEFT put_pixel(dst,win->posx+win->width-1,y,0xffffff); //RIGHT } } // } static void put_bg(uint8_t *dst) { while(ringbuffer_has(&bg_invl)) { int ry=ringbuffer_get(&bg_invl)+256*ringbuffer_get(&bg_invl); int rx=ringbuffer_get(&bg_invl)+256*ringbuffer_get(&bg_invl); int rh=ringbuffer_get(&bg_invl)+256*ringbuffer_get(&bg_invl); int rw=ringbuffer_get(&bg_invl)+256*ringbuffer_get(&bg_invl); cpy_rect(bgimage,rx,ry, // from dst,rx,ry, // to rw,rh, // 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,bool before) { 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; } if(before) { cpy_rect(bgimage,last_put_mouse_x,last_put_mouse_y, // from dst, last_put_mouse_x,last_put_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 false, // transparency color key 0xffffff // color key of transp ,false ); return; } last_put_mouse_x=mouse_x; last_put_mouse_y=mouse_y; cpy_rect(icon_data,iconx,icony, // from dst, 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 ,false ); } void compositor_del_window(uint32_t addr) { for(int i=0;i=MAX_WINDOWS)kpanic("max number of windows reached. increase MAX_WINDOWS"); windows[next_window]=windows[0]; windows[0].posx=next_x; windows[0].posy=next_y; next_x+=100; next_y+=100; windows[0].width=640; windows[0].height=400; windows[0].active=0; windows[0].vmem=addr; windows[0].pid=pid; windows[0].invl=r; windows[0].draw_border=true; windows[0].draw_meat=true; next_window++; compositor_mouse_handle(0,0,0); } // TODO : TEXTMODE FALLBACK! void compositor_init(uint16_t width, uint16_t height, uint16_t depth, uint16_t pitch) { bg_invl=ringbuffer_init(3); vesa_width=width; vesa_height=height; vesa_depth=depth/8; vesa_pitch=pitch; int icon_count=5; next_icon_x=width/2-icon_count*130/2; next_icon_y=height-130; klog("initialized composing window manager to %d x %d x %d" ,width,height,depth); uint16_t expected_pitch=width*depth/8; klog("expected pitch = %d , actual pitch = %d",expected_pitch,pitch); if(expected_pitch!=pitch)kpanic("sorry we need to fix this. padding not supported now"); add_icon("vim"); add_icon("vim"); add_icon("vim"); add_icon("vim"); add_icon("vim"); add_icon("vim"); compositor_mouse_handle(200,200,0); } void compositor_wake() { skip_render=false; } void compositor_wake2() { skip_render2=false; } void compositor_swap_buffers() { //if(skip_render||skip_render2)return; if(skip_render2)return; // force rate skip_render=true; skip_render2=true; static frames=0; static uint64_t last=0; if(!last)last=timer_get_ms(); uint64_t now=timer_get_ms(); frames++; if(now-last>3000) { klog("fps: %d",frames*1000/(now-last)); last=now; frames=0; } static bool first=true; if(first)memcpy(VMEM_FRAMEBUFFER,bgimage,vesa_pitch*vesa_height);// TODO optimize? rects only too?? first=false; put_bg(VMEM_FRAMEBUFFER); put_mouse(VMEM_FRAMEBUFFER,true); for(int i=next_window-1;i>=0;i--) { put_win(VMEM_FRAMEBUFFER,&windows[i]); } for(int i=next_icon-1;i>=0;i--) { // put_icon(backbuffer,&icons[i]); } put_mouse(VMEM_FRAMEBUFFER,false); // TODO optimize? rects only too? // 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; 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;iw->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; } else { w->active=false; } } if(active_win&&active!=-1&&active!=0&&(key&1)) { struct window temp; temp=windows[active]; windows[active]=windows[0]; windows[0]=temp; } lastkey=key; } // load background image or generate one if (param == 0) void compositor_set_background(char *ppm_raw_filename) { // TODO: think about funny things to do with timer and update // some generated / or modified bg regularly // // uint64_t t=timer_get_ms()/333; // klog("loading theme..."); fd bg=mount_file_open(ppm_raw_filename); uint32_t i=0; // read the image from left to right line by line for(int y=0;y<1080;y++) for(int x=0;x<1920;x++) { { uint32_t val=(fd_read(&bg)<<16)+(fd_read(&bg)<<8)+fd_read(&bg); if(x>=vesa_width)continue; if(y>=vesa_height)continue; put_pixel(icon_data,x,y,val); i++; } } klog("finished"); // generating simple background... int center_x=vesa_width/2; int center_y=vesa_height/2; int max_dist = center_x*center_x+center_y*center_y; for(int x=0;x