X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FApplications%2Faxwin3_src%2FWM%2Fwm.c;h=2478151280e052087d953390115ed317f6564f11;hb=0c35f45b89f715d4a62e4a1063b806d82b538872;hp=eddd12defe3b5af5eb2c4a2214345740b14f7450;hpb=7f1cbeafb4acc13d0cc7c11ac47df3efe473c106;p=tpg%2Facess2.git diff --git a/Usermode/Applications/axwin3_src/WM/wm.c b/Usermode/Applications/axwin3_src/WM/wm.c index eddd12de..24781512 100644 --- a/Usermode/Applications/axwin3_src/WM/wm.c +++ b/Usermode/Applications/axwin3_src/WM/wm.c @@ -10,18 +10,27 @@ #include #include #include +#include +#include + +// === IMPORTS === +extern void IPC_SendWMMessage(tIPC_Client *Client, uint32_t Src, uint32_t Dst, int Msg, int Len, const void *Data); // === GLOBALS === tWMRenderer *gpWM_Renderers; tWindow *gpWM_RootWindow; +//! Window which will recieve the next keyboard event +tWindow *gpWM_FocusedWindow; +//! Hilighted window (owner of the currently focused window) +tWindow *gpWM_HilightedWindow; // === CODE === void WM_Initialise(void) { - WM_CreateWindow(NULL, 0x0088FF, "Background"); + WM_CreateWindow(NULL, NULL, 0, 0x0088FF, "Background"); gpWM_RootWindow->W = giScreenWidth; gpWM_RootWindow->H = giScreenHeight; - gpWM_RootWindow->Flags = WINFLAG_SHOW; + gpWM_RootWindow->Flags = WINFLAG_SHOW|WINFLAG_NODECORATE; } void WM_RegisterRenderer(tWMRenderer *Renderer) @@ -32,7 +41,7 @@ void WM_RegisterRenderer(tWMRenderer *Renderer) } // --- Manipulation -tWindow *WM_CreateWindow(tWindow *Parent, int RendererArg, const char *RendererName) +tWindow *WM_CreateWindow(tWindow *Parent, tIPC_Client *Client, uint32_t ID, int RendererArg, const char *RendererName) { tWMRenderer *renderer; tWindow *ret; @@ -46,30 +55,39 @@ tWindow *WM_CreateWindow(tWindow *Parent, int RendererArg, const char *RendererN if(renderer == NULL) return NULL; - if(!Parent) - Parent = gpWM_RootWindow; - // - Call create window function ret = renderer->CreateWindow(RendererArg); + ret->Client = Client; + ret->ID = ID; ret->Parent = Parent; + if(!ret->Parent) + ret->Parent = gpWM_RootWindow; + ret->Owner = Parent; ret->Renderer = renderer; - ret->Flags = WINFLAG_CLEAN; // Note, not acutally clean, but it makes invaidate work + ret->Flags |= WINFLAG_CLEAN; // Needed to stop invaildate early exiting // Append to parent - if(Parent) + if(ret->Parent) { - if(Parent->LastChild) - Parent->LastChild->NextSibling = ret; + if(ret->Parent->LastChild) + ret->Parent->LastChild->NextSibling = ret; else - Parent->FirstChild = ret; - ret->PrevSibling = Parent->LastChild; - Parent->LastChild = ret; + ret->Parent->FirstChild = ret; + ret->PrevSibling = ret->Parent->LastChild; + ret->Parent->LastChild = ret; + ret->NextSibling = NULL; } else { gpWM_RootWindow = ret; } + // Don't decorate child windows by default + if(Parent) + { + ret->Flags |= WINFLAG_NODECORATE; + } + // - Return! return ret; } @@ -84,13 +102,111 @@ tWindow *WM_CreateWindowStruct(size_t ExtraSize) return ret; } +void WM_SetWindowTitle(tWindow *Window, const char *Title) +{ + if(Window->Title) + free(Window->Title); + Window->Title = strdup(Title); + _SysDebug("Window %p title set to '%s'", Window, Title); +} + +void WM_RaiseWindow(tWindow *Window) +{ + tWindow *parent = Window->Parent; + if(!Window->Parent) return ; + + // Remove from list + if(Window->PrevSibling) + Window->PrevSibling->NextSibling = Window->NextSibling; + if(Window->NextSibling) + Window->NextSibling->PrevSibling = Window->PrevSibling; + if(parent->FirstChild == Window) + parent->FirstChild = Window->NextSibling; + if(parent->LastChild == Window) + parent->LastChild = Window->PrevSibling; + + // Append to end + if(parent->LastChild) + parent->LastChild->NextSibling = Window; + else + parent->FirstChild = Window; + Window->PrevSibling = parent->LastChild; + Window->NextSibling = NULL; + parent->LastChild = Window; +} + +void WM_FocusWindow(tWindow *Destination) +{ + struct sWndMsg_Bool _msg; + + if( gpWM_FocusedWindow == Destination ) + return ; + if( Destination && !(Destination->Flags & WINFLAG_SHOW) ) + return ; + + _msg.Val = 0; + WM_SendMessage(NULL, gpWM_FocusedWindow, WNDMSG_FOCUS, sizeof(_msg), &_msg); + _msg.Val = 1; + WM_SendMessage(NULL, Destination, WNDMSG_FOCUS, sizeof(_msg), &_msg); + + WM_Invalidate(gpWM_FocusedWindow); + WM_Invalidate(Destination); + gpWM_FocusedWindow = Destination; + + + // Get the owner of the focused window +// while(Destination && Destination->Owner) Destination = Destination->Owner; +// gpWM_HilightedWindow = Destination; +} + + void WM_ShowWindow(tWindow *Window, int bShow) { - // TODO: Message window + struct sWndMsg_Bool _msg; + + if( !!(Window->Flags & WINFLAG_SHOW) == bShow ) + return ; + + // Message window + _msg.Val = !!bShow; + WM_SendMessage(NULL, Window, WNDMSG_SHOW, sizeof(_msg), &_msg); + + // Update the flag if(bShow) Window->Flags |= WINFLAG_SHOW; else + { Window->Flags &= ~WINFLAG_SHOW; + + if( Window == gpWM_FocusedWindow ) + WM_FocusWindow(Window->Parent); + + // Just a little memory saving for large hidden windows + if(Window->RenderBuffer) { + free(Window->RenderBuffer); + Window->RenderBuffer = NULL; + } + } + + WM_Invalidate(Window); +} + +void WM_DecorateWindow(tWindow *Window, int bDecorate) +{ + if( !(Window->Flags & WINFLAG_NODECORATE) == !!bDecorate ) + return ; + + if(bDecorate) + Window->Flags &= ~WINFLAG_NODECORATE; + else + Window->Flags |= WINFLAG_NODECORATE; + + // Needed because the window size changes + if(Window->RenderBuffer) { + free(Window->RenderBuffer); + Window->RenderBuffer = NULL; + } + WM_Invalidate(Window); } @@ -114,36 +230,84 @@ int WM_ResizeWindow(tWindow *Window, int W, int H) if(W <= 0 || H <= 0 ) return 1; if(Window->X + W < 0) Window->X = -W + 1; if(Window->Y + H < 0) Window->Y = -H + 1; - + Window->W = W; Window->H = H; + if(Window->RenderBuffer) { + free(Window->RenderBuffer); + Window->RenderBuffer = NULL; + } WM_Invalidate(Window); + + { + struct sWndMsg_Resize msg; + msg.W = W; + msg.H = H; + WM_SendMessage(NULL, Window, WNDMSG_RESIZE, sizeof(msg), &msg); + } return 0; } +int WM_SendMessage(tWindow *Source, tWindow *Dest, int Message, int Length, const void *Data) +{ + if(Dest == NULL) return -2; + if(Length > 0 && Data == NULL) return -1; + + if( Decorator_HandleMessage(Dest, Message, Length, Data) != 1 ) + { + // TODO: Catch errors from ->HandleMessage + return 0; + } + + // ->HandleMessage returns 1 when the message was not handled + if( Dest->Renderer->HandleMessage(Dest, Message, Length, Data) != 1 ) + { + // TODO: Catch errors from ->HandleMessage + return 0; + } + + // TODO: Implement message masking + + if(Dest->Client) + { + uint32_t src_id; + if(!Source) + src_id = -1; + else if(Source->Client != Dest->Client) { + // TODO: Support different client source windows + _SysDebug("WM_SendMessage: TODO - Support inter-client messages"); + return -1; + } + else { + src_id = Source->ID; + } + + IPC_SendWMMessage(Dest->Client, src_id, Dest->ID, Message, Length, Data); + } + + return 1; +} + void WM_Invalidate(tWindow *Window) { + if(!Window) return ; + _SysDebug("Invalidating %p", Window); // Don't invalidate twice (speedup) - if( !(Window->Flags & WINFLAG_CLEAN) ) return; +// if( !(Window->Flags & WINFLAG_CLEAN) ) return; - _SysDebug("Invalidating %p"); - // Mark for re-render Window->Flags &= ~WINFLAG_CLEAN; // Mark up the tree that a child window has changed while( (Window = Window->Parent) ) - { - _SysDebug("Childclean removed from %p", Window); Window->Flags &= ~WINFLAG_CHILDCLEAN; - } } // --- Rendering / Update void WM_int_UpdateWindow(tWindow *Window) { - tWindow *child; + int bDecoratorRedraw = 0; // Ignore hidden windows if( !(Window->Flags & WINFLAG_SHOW) ) @@ -152,6 +316,25 @@ void WM_int_UpdateWindow(tWindow *Window) // Render if( !(Window->Flags & WINFLAG_CLEAN) ) { + // Calculate RealW/RealH + if( !(Window->Flags & WINFLAG_NODECORATE) ) + { + _SysDebug("Applying decorations to %p", Window); + Decorator_UpdateBorderSize(Window); + Window->RealW = Window->BorderL + Window->W + Window->BorderR; + Window->RealH = Window->BorderT + Window->H + Window->BorderB; + bDecoratorRedraw = 1; + } + else + { + Window->BorderL = 0; + Window->BorderR = 0; + Window->BorderT = 0; + Window->BorderB = 0; + Window->RealW = Window->W; + Window->RealH = Window->H; + } + Window->Renderer->Redraw(Window); Window->Flags |= WINFLAG_CLEAN; } @@ -159,6 +342,7 @@ void WM_int_UpdateWindow(tWindow *Window) // Process children if( !(Window->Flags & WINFLAG_CHILDCLEAN) ) { + tWindow *child; for( child = Window->FirstChild; child; child = child->NextSibling ) { WM_int_UpdateWindow(child); @@ -166,6 +350,8 @@ void WM_int_UpdateWindow(tWindow *Window) Window->Flags |= WINFLAG_CHILDCLEAN; } + if( bDecoratorRedraw ) + Decorator_Redraw(Window); } void WM_int_BlitWindow(tWindow *Window) @@ -175,9 +361,21 @@ void WM_int_BlitWindow(tWindow *Window) // Ignore hidden windows if( !(Window->Flags & WINFLAG_SHOW) ) return ; + +// _SysDebug("Blit %p to (%i,%i) %ix%i", Window, Window->X, Window->Y, Window->RealW, Window->RealH); + Video_Blit(Window->RenderBuffer, Window->X, Window->Y, Window->RealW, Window->RealH); - Video_Blit(Window->RenderBuffer, Window->X, Window->Y, Window->W, Window->H); - + if( Window == gpWM_FocusedWindow && Window->CursorW ) + { + Video_FillRect( + Window->X + Window->BorderL + Window->CursorX, + Window->Y + Window->BorderT + Window->CursorY, + Window->CursorW, Window->CursorH, + 0x000000 + ); + + } + for( child = Window->FirstChild; child; child = child->NextSibling ) { WM_int_BlitWindow(child); @@ -199,140 +397,3 @@ void WM_Update(void) Video_Update(); } -// --- WM Render Routines -// TODO: Move to another file? -void WM_Render_FillRect(tWindow *Window, int X, int Y, int W, int H, tColour Colour) -{ - uint32_t *dest; - int i; - _SysDebug("WM_Render_FilledRect(%p, 0x%x...", Window, Colour); - _SysDebug(" (%i,%i), %ix%i)", X, Y, W, H); - // Clip to window dimensions - if(X < 0) { W += X; X = 0; } - if(Y < 0) { H += Y; Y = 0; } - if(X >= Window->W) return; - if(Y >= Window->H) return; - if(X + W > Window->W) W = Window->W - X; - if(Y + H > Window->H) H = Window->H - Y; - _SysDebug(" Clipped to (%i,%i), %ix%i", X, Y, W, H); - - // Render to buffer - // Create if needed? - - if(!Window->RenderBuffer) { - Window->RenderBuffer = malloc(Window->W*Window->H*4); - } - - dest = (uint32_t*)Window->RenderBuffer + Y*Window->W + X; - while( H -- ) - { - for( i = W; i --; ) - *dest++ = Colour; - dest += Window->W - W; - } -} - -void WM_Render_DrawRect(tWindow *Window, int X, int Y, int W, int H, tColour Colour) -{ - WM_Render_FillRect(Window, X, Y, W, 1, Colour); - WM_Render_FillRect(Window, X, Y+H-1, W, 1, Colour); - WM_Render_FillRect(Window, X, Y, 1, H, Colour); - WM_Render_FillRect(Window, X+W-1, Y, 1, H, Colour); -} - -void WM_Render_DrawText(tWindow *Window, int X, int Y, int W, int H, void *Font, tColour Colour, const char *Text) -{ - // TODO: Implement -} - -/** - * \brief Draw an image to the screen - * \todo Maybe have support for an offset in the image - */ -void WM_Render_DrawImage(tWindow *Window, int X, int Y, int W, int H, tImage *Image) -{ - int x, y; - uint32_t *dest; - uint8_t *data; - - // Sanity please - if( !Image ) return ; - - // Allocate - if(!Window->RenderBuffer) { - Window->RenderBuffer = malloc(Window->W*Window->H*4); - } - - // Bounds Check - if( X >= Window->W ) return ; - if( Y >= Window->H ) return ; - - // Wrap to image size - if( W > Image->Width ) W = Image->Width; - if( H > Image->Height ) H = Image->Height; - - // Wrap to screen size - if( X + W > Window->W ) W = Window->W - X; - if( Y + H > Window->H ) H = Window->H - Y; - - dest = (uint32_t*)Window->RenderBuffer + Y * Window->W + X; - data = Image->Data; - - // Do the render - switch( Image->Format ) - { - case IMGFMT_BGRA: - for( y = 0; y < H; y ++ ) - { - int r, g, b, a; // New - int or, og, ob; // Original - for( x = 0; x < W; x ++ ) - { - b = data[x*4+0]; g = data[x*4+1]; r = data[x*4+2]; a = data[x*4+3]; - if( a == 0 ) continue; // 100% transparent - ob = dest[x]&0xFF; og = (dest[x] >> 8)&0xFF; or = (dest[x] >> 16)&0xFF; - // Handle Alpha - switch(a) - { - // Transparent: Handled above - // Solid - case 0xFF: break; - // Half - case 0x80: - r = (or + r) / 2; - g = (og + g) / 2; - b = (ob + b) / 2; - break; - // General - default: - r = (or * (255-a) + r * a) / 255; - g = (og * (255-a) + g * a) / 255; - b = (ob * (255-a) + b * a) / 255; - break; - } - dest[x] = b | (g << 8) | (r << 16); - } - data += Image->Width * 4; - dest += Window->W; - } - break; - - // RGB - case IMGFMT_RGB: - for( y = 0; y < H; y ++ ) - { - for( x = 0; x < W; x ++ ) - { - // Blue Green Red - dest[x] = data[x*3+2] | (data[x*3+1] << 8) | (data[x*3+0] << 16); - } - data += W * 3; - dest += Window->W; - } - break; - default: - _SysDebug("ERROR: Unknown image format %i\n", Image->Format); - break; - } -} -