#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 100 struct window { uint32_t pid; struct pdirectory *vmem; int16_t posx; int16_t posy; uint16_t width; uint16_t height; uint32_t color; uint16_t active; }; struct window windows[MAX_WINDOWS]; static uint8_t backbuffer [VESA_MAX_WIDTH*VESA_MAX_HEIGHT*4]; static uint8_t icons [1920*1080*4]; static uint16_t next_window=0; static uint16_t next_x=50; static uint16_t next_y=50; 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=25; static int mouse_icon_active_ly=0; // costly but beautiful static bool option_blending=false; // so disable ! :P // 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) { uint32_t *p=dst+y*vesa_pitch+x*vesa_depth; *p=color; } /** retrieves single pixel from src without bound checking */ static uint32_t get_pixel(uint8_t *src, int x,int y) { uint32_t *p=src+y*vesa_pitch+x*vesa_depth; return *p; } 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 ) { // TODO optimize! for(int x=0;xvmem); uint32_t *user_vmem=VMEM_USER_FRAMEBUFFER; uint32_t userx=0; uint32_t usery=0; // iterate over complete window area for(uint16_t x=win->posx;xposx+win->width;x++) { usery=0; for(uint16_t y=win->posy;yposy+win->height;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; //we encoded alpha in the highest octet. 1-opaque 0-transparent //no premultiplied alpha. TODO: change maybe for speedup!? 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; */ } else { put_pixel(backbuffer,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) { for(uint16_t x=win->posx;xposx+win->width;x++) { put_pixel(backbuffer,x,win->posy,0xffffff); //TOP put_pixel(backbuffer,x,win->posy+win->height-1,0xffffff); //BOTTOM } for(uint16_t y=win->posy;yposy+win->height;y++) { put_pixel(backbuffer,win->posx,y,0xffffff); //LEFT put_pixel(backbuffer,win->posx+win->width-1,y,0xffffff); //RIGHT } } // } static void put_mouse() { int iconx=mouse_icon_lx; int icony=mouse_icon_ly; if(mouse_k&1) { iconx=mouse_icon_active_lx; icony=mouse_icon_active_ly; } cpy_rect(icons,iconx,icony, // from backbuffer, 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 0xffffff // color key of transp ); } 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=480; windows[0].color=0xAAAA00AA; windows[0].active=0; windows[0].vmem=addr; windows[0].pid=pid; next_window++; compositor_mouse_handle(200,200,0); } // TODO : TEXTMODE FALLBACK! void compositor_init(uint16_t width, uint16_t height, uint16_t depth, uint16_t pitch) { vesa_width=width; vesa_height=height; vesa_depth=depth/8; vesa_pitch=pitch; 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"); } void compositor_wake() { skip_render=false; } void compositor_wake2() { skip_render2=false; } void compositor_swap_buffers() { if(skip_render||skip_render2)return; skip_render=true; skip_render2=true; static bool first=true; // if(!first)return; // klog("swap"); // background // memcpy(backbuffer,bgimage,vesa_height*vesa_width*4);// TODO optimize? rects only too? // compositor_set_background(0); for(int i=next_window-1;i>=0;i--) { put_win(&windows[i]); } put_mouse(); // TODO optimize? rects only too? memcpy(VMEM_FRAMEBUFFER,backbuffer,vesa_height*vesa_width*vesa_depth); first=false; } 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); } } } void compositor_mouse_handle(int16_t diff_x,int16_t diff_y, uint8_t key) { // klog("%d %d %d",diff_x,diff_y,key); 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; 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; } } if(active!=-1&&active!=0&&(key&1)) { struct window temp; temp=windows[active]; windows[active]=windows[0]; windows[0]=temp; } } // 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(icons,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