X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FApplications%2Faxwin2_src%2FWM%2Fwm.c;h=1bc8db2c8090a807d058c911c8b3c91cd40642fb;hb=7941d6b368acb0abc17e6a77ffaf7b4c306b67ab;hp=e4d45b5c0457cdcd93f233ea868f24e84c9d5c74;hpb=43992cf707ec82f8ffd3a1500ad5952640335a6d;p=tpg%2Facess2.git diff --git a/Usermode/Applications/axwin2_src/WM/wm.c b/Usermode/Applications/axwin2_src/WM/wm.c index e4d45b5c..1bc8db2c 100644 --- a/Usermode/Applications/axwin2_src/WM/wm.c +++ b/Usermode/Applications/axwin2_src/WM/wm.c @@ -8,38 +8,154 @@ #include #include #include "wm.h" +#include // _SysDebug // === IMPORTS === -extern void Decorator_RenderWidget(tElement *Element); extern void Video_GetTextDims(tFont *Font, const char *Text, int *W, int *H); // === PROTOTYPES === +tApplication *AxWin_RegisterClient(tIPC_Type *IPCType, void *Ident, const char *Name); +void AxWin_DeregisterClient(tApplication *App); +tApplication *AxWin_GetClient(tIPC_Type *Method, void *Ident); tElement *AxWin_CreateElement(tElement *Parent, int Type, int Flags, const char *DebugName); void AxWin_DeleteElement(tElement *Element); void AxWin_SetFlags(tElement *Element, int Flags); void AxWin_SetSize(tElement *Element, int Size); void AxWin_SetText(tElement *Element, const char *Text); -void WM_UpdateMinDims(tElement *Element); -void WM_UpdateDimensions(tElement *Element, int Pass); -void WM_UpdatePosition(tElement *Element); -void WM_RenderWidget(tElement *Element); -void WM_Update(void); // === GLOBALS === +// - TODO: Handle windows by having multiple root elements tElement gWM_RootElement = { .DebugName = "ROOT" }; +tWindow *gWM_WindowFirst; +tWindow *gWM_WindowLast; +tApplication *gWM_Applications; + int giWM_MaxAreaX = 0; + int giWM_MaxAreaY = 0; + int giWM_MaxAreaW = -1; + int giWM_MaxAreaH = -1; + +// --- Element type flags struct { void (*Init)(tElement *This); + void (*Delete)(tElement *This); void (*UpdateFlags)(tElement *This); void (*UpdateSize)(tElement *This); void (*UpdateText)(tElement *This); } gaWM_WidgetTypes[MAX_ELETYPES] = { - {NULL, NULL, NULL, NULL}, // NULL - {NULL, NULL, NULL, NULL} // Box + {NULL, NULL, NULL, NULL, NULL}, // NULL + {NULL, NULL, NULL, NULL, NULL}, // Window + {NULL, NULL, NULL, NULL, NULL} // Box }; +const int ciWM_NumWidgetTypes = sizeof(gaWM_WidgetTypes)/sizeof(gaWM_WidgetTypes[0]); // === CODE === +tApplication *AxWin_RegisterClient(tIPC_Type *Method, void *Ident, const char *Name) +{ + int identlen = Method->GetIdentSize(Ident); + // Structure, empty string, Name, Ident + tApplication *ret = calloc( 1, sizeof(tApplication) + 1 + strlen(Name) + 1 + identlen ); + + // DebugName is empty + + // Name/Title + ret->Name = &ret->MetaElement.DebugName[1]; + strcpy(ret->Name, Name); + // Ident + ret->Ident = ret->Name + strlen(Name) + 1; + memcpy(ret->Ident, Ident, identlen); + // IPC Type + ret->IPCType = Method; + + // Element index + ret->MaxElementIndex = DEFAULT_ELEMENTS_PER_APP; + ret->EleIndex = calloc( 1, ret->MaxElementIndex * sizeof(*ret->EleIndex) ); + + // Add to global list + ret->Next = gWM_Applications; + gWM_Applications = ret; + + // TODO: Inform listeners of the new application + + return ret; +} + +void AxWin_DeregisterClient(tApplication *App) +{ + // TODO: Complete implementing DeregisterClient + tElement *win, *next; + + for( win = App->MetaElement.FirstChild; win; win = next ) + { + next = win->NextSibling; + AxWin_DeleteElement(win); + } + + // TODO: Inform listeners of deleted application + + // Remove from list + { + tApplication *app, *prev = NULL; + for( app = gWM_Applications; app; app = app->Next ) + { + if( app == App ) break; + prev = app; + } + + if( app ) + { + if(prev) + prev->Next = App->Next; + else + gWM_Applications = App->Next; + } + } + + free(App); +} + +/** + * \brief Get an application handle from a client identifier + */ +tApplication *AxWin_GetClient(tIPC_Type *Method, void *Ident) +{ + // TODO: Faster and smarter technique + tApplication *app; + for( app = gWM_Applications; app; app = app->Next ) + { + if( app->IPCType != Method ) continue; + if( Method->CompareIdent( app->Ident, Ident ) != 0 ) continue; + return app; + } + return NULL; +} + +tElement *AxWin_CreateAppWindow(tApplication *App, const char *Name) +{ + tElement *ret; + tWindow *win; + + win = calloc(sizeof(tWindow) + 1); + if(!win) return NULL; + + ret = &win->Element; + ret->Type = ELETYPE_WINDOW; + ret->Data = win; + ret->Parent = &App->MetaElement; + + // Add to parent list + if(ret->Parent->LastChild) + ret->Parent->LastChild->NextSibling = ret; + ret->Parent->LastChild = ret; + if(!ret->Parent->FirstChild) + ret->Parent->FirstChild = ret; + + ret->Text = strdup(Name); + + return ret; +} + // --- Widget Creation and Control --- tAxWin_Element *AxWin_CreateElement(tElement *Parent, int Type, int Flags, const char *DebugName) { @@ -67,7 +183,7 @@ tAxWin_Element *AxWin_CreateElement(tElement *Parent, int Type, int Flags, const ret->PaddingT = 2; ret->PaddingB = 2; - if( gaWM_WidgetTypes[Type].Init ) + if( Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[Type].Init ) gaWM_WidgetTypes[Type].Init(ret); WM_UpdateMinDims(ret->Parent); @@ -76,11 +192,31 @@ tAxWin_Element *AxWin_CreateElement(tElement *Parent, int Type, int Flags, const } /** - * \brief + * \brief Delete an element */ void AxWin_DeleteElement(tElement *Element) { + tElement *child, *next; + + for(child = Element->FirstChild; child; child = next) + { + next = child->NextSibling; + AxWin_DeleteElement(child); + } + // TODO: Implement AxWin_DeleteElement + // TODO: Clean up related data. + if( Element->Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[Element->Type].Delete ) + gaWM_WidgetTypes[Element->Type].Delete(Element); + + if(Element->Owner) + Element->Owner->EleIndex[ Element->ApplicationID ] = NULL; + + Element->Type = 0; + Element->Owner = 0; + Element->Flags = 0; + + free(Element); } /** @@ -98,6 +234,9 @@ void AxWin_SetFlags(tElement *Element, int Flags) return ; } +/** + * \brief Set the fixed lenghthways size of an element + */ void AxWin_SetSize(tElement *Element, int Size) { if(!Element) return ; @@ -153,276 +292,9 @@ void AxWin_SetText(tElement *Element, const char *Text) } } break; + default: // Any other, no special case + break ; } return ; } - -// --- Pre-Rendering --- -/** - * \name Pre-Rendering - * \brief Updates the element positions and sizes - * \{ - */ -/** - * \brief Updates the dimensions of an element - * - * The dimensions of an element are calculated from the parent's - * cross dimension (the side at right angles to the alignment) sans some - * padding. - */ -void WM_UpdateDimensions(tElement *Element, int Pass) -{ - tElement *child; - int nChildren = 0; - int nFixed = 0; - int maxCross = 0; - int fixedSize = 0; - int fullCross, dynWith; - - _SysDebug("WM_UpdateDimensions %p'%s'", Element, Element->DebugName); - _SysDebug(" -> Flags = 0x%x", Element->Flags); - _SysDebug(" ->CachedH = %i, ->PaddingT = %i, ->PaddingB = %i", - Element->CachedH, Element->PaddingT, Element->PaddingB - ); - _SysDebug(" ->CachedW = %i, ->PaddingL = %i, ->PaddingR = %i", - Element->CachedW, Element->PaddingL, Element->PaddingR - ); - - // Pass 1 - for( child = Element->FirstChild; child; child = child->NextSibling ) - { - if( child->Flags & ELEFLAG_ABSOLUTEPOS ) - continue ; - - _SysDebug(" > %p'%s' ->FixedWith = %i", child, child->DebugName, child->FixedWith); - if( child->FixedWith ) - { - nFixed ++; - fixedSize += child->FixedWith; - } - - if( child->FixedCross && maxCross < child->FixedCross ) - maxCross = child->FixedCross; - if( child->MinCross && maxCross < child->MinCross ) - maxCross = child->MinCross; - nChildren ++; - } - - _SysDebug(" - nChildren = %i, nFixed = %i", Element, nChildren, nFixed); - if( nChildren > nFixed ) { - if( Element->Flags & ELEFLAG_VERTICAL ) - dynWith = Element->CachedH - Element->PaddingT - - Element->PaddingB; - else - dynWith = Element->CachedW - Element->PaddingL - - Element->PaddingR; - dynWith -= fixedSize; - if( dynWith < 0 ) return ; - dynWith /= nChildren - nFixed; - _SysDebug(" - dynWith = %i", dynWith); - } - - if( Element->Flags & ELEFLAG_VERTICAL ) - fullCross = Element->CachedW - Element->PaddingL - Element->PaddingR; - else - fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB; - - _SysDebug(" - fullCross = %i", Element, fullCross); - - // Pass 2 - Set sizes and recurse - for( child = Element->FirstChild; child; child = child->NextSibling ) - { - int cross, with; - - _SysDebug(" > %p'%s' ->MinCross = %i", child, child->DebugName, child->MinCross); - - - // --- Cross Size --- - if( child->FixedCross ) - cross = child->FixedCross; - // Expand to fill? - // TODO: Extra flag so options are (Expand, Equal, Wrap) - else if( child->Flags & ELEFLAG_NOEXPAND ) - cross = child->MinCross; - else - cross = fullCross; - _SysDebug(" > %p'%s' - cross = %i", child, child->DebugName, cross); - if( Element->Flags & ELEFLAG_VERTICAL ) - child->CachedW = cross; - else - child->CachedH = cross; - - // --- With Size --- - if( child->FixedWith) - with = child->FixedWith; - else if( child->Flags & ELEFLAG_NOSTRETCH ) - with = child->MinWith; - else - with = dynWith; - _SysDebug(" > %p'%s' - with = %i", child, child->DebugName, with); - if( Element->Flags & ELEFLAG_VERTICAL ) - child->CachedH = with; - else - child->CachedW = with; - - WM_UpdateDimensions(child, 0); - } - - _SysDebug("%p'%s' Done", Element, Element->DebugName); -} - -/** - * \brief Updates the position of an element - * - * The parent element sets the positions of its children - */ -void WM_UpdatePosition(tElement *Element) -{ - tElement *child; - int x, y; - static int depth = 0; - char indent[depth+1]; - - if( Element->Flags & ELEFLAG_NORENDER ) return ; - - memset(indent, ' ', depth); - indent[depth] = '\0'; - depth ++; - - _SysDebug("%sWM_UpdatePosition %p'%s'{PaddingL:%i, PaddingT:%i}", - indent, Element, Element->DebugName, Element->PaddingL, Element->PaddingT); - - // Initialise - x = Element->CachedX + Element->PaddingL; - y = Element->CachedY + Element->PaddingT; - - _SysDebug("%s- Alignment = %s", indent, - (Element->Flags & ELEFLAG_VERTICAL) ? "vertical" : "horizontal"); - - // Update each child - for(child = Element->FirstChild; child; child = child->NextSibling) - { - _SysDebug("%s- x = %i, y = %i", indent, x, y); - child->CachedX = x; - child->CachedY = y; - - // Set Alignment - if( Element->Flags & ELEFLAG_ALIGN_CENTER ) { - _SysDebug("%sChild being aligned to center", indent); - if(Element->Flags & ELEFLAG_VERTICAL) - child->CachedX += Element->CachedW/2 - child->CachedW/2; - else - child->CachedY += Element->CachedH/2 - child->CachedH/2; - } - else if( Element->Flags & ELEFLAG_ALIGN_END) { - _SysDebug("%sChild being aligned to end", indent); - if(Element->Flags & ELEFLAG_VERTICAL ) - child->CachedX += Element->CachedW - - Element->PaddingL - Element->PaddingR - - child->CachedW; - else - child->CachedY += Element->CachedH - - Element->PaddingT - - Element->PaddingB - - child->CachedH; - } - - _SysDebug("%s> %p'%s' at (%i,%i)", indent, child, child->DebugName, - child->CachedX, child->CachedY); - - // Update child's children positions - WM_UpdatePosition(child); - - // Increment - if(Element->Flags & ELEFLAG_VERTICAL ) { - y += child->CachedH + Element->GapSize; - } - else { - x += child->CachedW + Element->GapSize; - } - } - - _SysDebug("%sElement %p'%s' (%i,%i)", - indent, Element, Element->DebugName, Element->CachedX, Element->CachedY - ); - depth --; -} - -/** - * \brief Update the minimum dimensions of the element - * \note Called after a child's minimum dimensions have changed - */ -void WM_UpdateMinDims(tElement *Element) -{ - tElement *child; - - if(!Element) return; - - Element->MinCross = 0; - Element->MinWith = 0; - - for(child = Element->FirstChild; child; child = child->NextSibling) - { - if( Element->Parent && - (Element->Flags & ELEFLAG_VERTICAL) == (Element->Parent->Flags & ELEFLAG_VERTICAL) - ) - { - if(child->FixedCross) - Element->MinCross += child->FixedCross; - else - Element->MinCross += child->MinCross; - if(child->FixedWith) - Element->MinWith += child->FixedWith; - else - Element->MinWith += child->MinWith; - } - else - { - if(child->FixedCross) - Element->MinWith += child->FixedCross; - else - Element->MinWith += child->MinCross; - if(child->FixedWith) - Element->MinCross += child->FixedWith; - else - Element->MinCross += child->MinWith; - } - } - - // Recurse upwards - WM_UpdateMinDims(Element->Parent); -} -/** - * \} - */ - -// --- Render --- -void WM_RenderWidget(tElement *Element) -{ - tElement *child; - - if( Element->Flags & ELEFLAG_NORENDER ) return ; - if( Element->Flags & ELEFLAG_INVISIBLE ) return ; - - Decorator_RenderWidget(Element); - - for(child = Element->FirstChild; child; child = child->NextSibling) - { - WM_RenderWidget(child); - } -} - -void WM_Update(void) -{ - gWM_RootElement.CachedX = 0; gWM_RootElement.CachedY = 0; - gWM_RootElement.CachedW = giScreenWidth; - gWM_RootElement.CachedH = giScreenHeight; - gWM_RootElement.Flags |= ELEFLAG_NOEXPAND|ELEFLAG_ABSOLUTEPOS|ELEFLAG_FIXEDSIZE; - - WM_UpdateDimensions( &gWM_RootElement, 0 ); - WM_UpdatePosition( &gWM_RootElement ); - WM_RenderWidget( &gWM_RootElement ); - - Video_Update(); -}