2 * Acess2 Window Manager v3
3 * - By John Hodge (thePowersGang)
6 * - Window manager core
9 #include <wm_renderer.h>
13 #include <wm_messages.h>
14 #include <decorator.h>
17 extern void IPC_SendWMMessage(tIPC_Client *Client, uint32_t Src, uint32_t Dst, int Msg, int Len, const void *Data);
20 tWMRenderer *gpWM_Renderers;
21 tWindow *gpWM_RootWindow;
22 //! Window which will recieve the next keyboard event
23 tWindow *gpWM_FocusedWindow;
26 void WM_Initialise(void)
28 WM_CreateWindow(NULL, NULL, 0, 0x0088FF, "Background");
29 gpWM_RootWindow->W = giScreenWidth;
30 gpWM_RootWindow->H = giScreenHeight;
31 gpWM_RootWindow->Flags = WINFLAG_SHOW|WINFLAG_NODECORATE;
34 void WM_RegisterRenderer(tWMRenderer *Renderer)
36 // TODO: Catch out duplicates
37 Renderer->Next = gpWM_Renderers;
38 gpWM_Renderers = Renderer;
42 tWindow *WM_CreateWindow(tWindow *Parent, tIPC_Client *Client, uint32_t ID, int RendererArg, const char *RendererName)
44 tWMRenderer *renderer;
48 for( renderer = gpWM_Renderers; renderer; renderer = renderer->Next )
50 if(strcmp(RendererName, renderer->Name) == 0)
57 Parent = gpWM_RootWindow;
59 // - Call create window function
60 ret = renderer->CreateWindow(RendererArg);
64 ret->Renderer = renderer;
65 ret->Flags |= WINFLAG_CLEAN; // Needed to stop invaildate early exiting
71 Parent->LastChild->NextSibling = ret;
73 Parent->FirstChild = ret;
74 ret->PrevSibling = Parent->LastChild;
75 Parent->LastChild = ret;
76 ret->NextSibling = NULL;
80 gpWM_RootWindow = ret;
83 // Don't decorate child windows by default
84 if(Parent != gpWM_RootWindow)
86 ret->Flags |= WINFLAG_NODECORATE;
93 tWindow *WM_CreateWindowStruct(size_t ExtraSize)
97 ret = calloc( sizeof(tWindow) + ExtraSize, 1 );
98 ret->RendererInfo = ret + 1; // Get end of tWindow
103 void WM_SetWindowTitle(tWindow *Window, const char *Title)
107 Window->Title = strdup(Title);
108 _SysDebug("Window %p title set to '%s'", Window, Title);
111 void WM_RaiseWindow(tWindow *Window)
113 tWindow *parent = Window->Parent;
114 if(!Window->Parent) return ;
117 if(Window->PrevSibling)
118 Window->PrevSibling->NextSibling = Window->NextSibling;
119 if(Window->NextSibling)
120 Window->NextSibling->PrevSibling = Window->PrevSibling;
121 if(parent->FirstChild == Window)
122 parent->FirstChild = Window->NextSibling;
123 if(parent->LastChild == Window)
124 parent->LastChild = Window->PrevSibling;
127 if(parent->LastChild)
128 parent->LastChild->NextSibling = Window;
130 parent->FirstChild = Window;
131 Window->PrevSibling = parent->LastChild;
132 Window->NextSibling = NULL;
133 parent->LastChild = Window;
136 void WM_FocusWindow(tWindow *Destination)
138 struct sWndMsg_Bool _msg;
140 if( gpWM_FocusedWindow == Destination )
142 if( Destination && !(Destination->Flags & WINFLAG_SHOW) )
146 WM_SendMessage(NULL, gpWM_FocusedWindow, WNDMSG_FOCUS, sizeof(_msg), &_msg);
148 WM_SendMessage(NULL, Destination, WNDMSG_FOCUS, sizeof(_msg), &_msg);
150 gpWM_FocusedWindow = Destination;
154 void WM_ShowWindow(tWindow *Window, int bShow)
157 struct sWndMsg_Bool _msg;
159 if( !!(Window->Flags & WINFLAG_SHOW) == bShow )
163 WM_SendMessage(NULL, Window, WNDMSG_SHOW, sizeof(_msg), &_msg);
166 Window->Flags |= WINFLAG_SHOW;
168 Window->Flags &= ~WINFLAG_SHOW;
169 if( Window == gpWM_FocusedWindow )
170 WM_FocusWindow(Window->Parent);
172 // Just a little memory saving for large hidden windows
173 if(Window->RenderBuffer) {
174 free(Window->RenderBuffer);
175 Window->RenderBuffer = NULL;
178 WM_Invalidate(Window);
181 void WM_DecorateWindow(tWindow *Window, int bDecorate)
183 if( !(Window->Flags & WINFLAG_NODECORATE) == !!bDecorate )
187 Window->Flags &= ~WINFLAG_NODECORATE;
189 Window->Flags |= WINFLAG_NODECORATE;
191 // Needed because the window size changes
192 if(Window->RenderBuffer) {
193 free(Window->RenderBuffer);
194 Window->RenderBuffer = NULL;
197 WM_Invalidate(Window);
200 int WM_MoveWindow(tWindow *Window, int X, int Y)
203 if(X + Window->W < 0) X = -Window->W + 1;
204 if(Y + Window->H < 0) Y = -Window->H + 1;
205 if(X >= giScreenWidth) X = giScreenWidth - 1;
206 if(Y >= giScreenHeight) Y = giScreenHeight - 1;
208 Window->X = X; Window->Y = Y;
210 WM_Invalidate(Window);
215 int WM_ResizeWindow(tWindow *Window, int W, int H)
217 if(W <= 0 || H <= 0 ) return 1;
218 if(Window->X + W < 0) Window->X = -W + 1;
219 if(Window->Y + H < 0) Window->Y = -H + 1;
221 Window->W = W; Window->H = H;
223 if(Window->RenderBuffer) {
224 free(Window->RenderBuffer);
225 Window->RenderBuffer = NULL;
227 WM_Invalidate(Window);
230 struct sWndMsg_Resize msg;
233 WM_SendMessage(NULL, Window, WNDMSG_RESIZE, sizeof(msg), &msg);
239 int WM_SendMessage(tWindow *Source, tWindow *Dest, int Message, int Length, const void *Data)
241 if(Dest == NULL) return -2;
242 if(Length > 0 && Data == NULL) return -1;
244 if( Decorator_HandleMessage(Dest, Message, Length, Data) != 1 )
246 // TODO: Catch errors from ->HandleMessage
250 // ->HandleMessage returns 1 when the message was not handled
251 if( Dest->Renderer->HandleMessage(Dest, Message, Length, Data) != 1 )
253 // TODO: Catch errors from ->HandleMessage
257 // TODO: Implement message masking
264 else if(Source->Client != Dest->Client) {
265 // TODO: Support different client source windows
266 _SysDebug("WM_SendMessage: TODO - Support inter-client messages");
273 IPC_SendWMMessage(Dest->Client, src_id, Dest->ID, Message, Length, Data);
279 void WM_Invalidate(tWindow *Window)
281 _SysDebug("Invalidating %p", Window);
282 // Don't invalidate twice (speedup)
283 // if( !(Window->Flags & WINFLAG_CLEAN) ) return;
285 // Mark for re-render
286 Window->Flags &= ~WINFLAG_CLEAN;
288 // Mark up the tree that a child window has changed
289 while( (Window = Window->Parent) )
290 Window->Flags &= ~WINFLAG_CHILDCLEAN;
293 // --- Rendering / Update
294 void WM_int_UpdateWindow(tWindow *Window)
298 // Ignore hidden windows
299 if( !(Window->Flags & WINFLAG_SHOW) )
303 if( !(Window->Flags & WINFLAG_CLEAN) )
305 // Calculate RealW/RealH
306 if( !(Window->Flags & WINFLAG_NODECORATE) )
308 _SysDebug("Applying decorations to %p", Window);
309 Decorator_UpdateBorderSize(Window);
310 Window->RealW = Window->BorderL + Window->W + Window->BorderR;
311 Window->RealH = Window->BorderT + Window->H + Window->BorderB;
312 Decorator_Redraw(Window);
320 Window->RealW = Window->W;
321 Window->RealH = Window->H;
324 Window->Renderer->Redraw(Window);
325 Window->Flags |= WINFLAG_CLEAN;
329 if( !(Window->Flags & WINFLAG_CHILDCLEAN) )
331 for( child = Window->FirstChild; child; child = child->NextSibling )
333 WM_int_UpdateWindow(child);
335 Window->Flags |= WINFLAG_CHILDCLEAN;
340 void WM_int_BlitWindow(tWindow *Window)
344 // Ignore hidden windows
345 if( !(Window->Flags & WINFLAG_SHOW) )
348 _SysDebug("Blit %p to (%i,%i) %ix%i", Window, Window->X, Window->Y, Window->RealW, Window->RealH);
349 Video_Blit(Window->RenderBuffer, Window->X, Window->Y, Window->RealW, Window->RealH);
351 for( child = Window->FirstChild; child; child = child->NextSibling )
353 WM_int_BlitWindow(child);
359 // Don't redraw if nothing has changed
360 if( (gpWM_RootWindow->Flags & WINFLAG_CHILDCLEAN) )
363 // - Iterate through visible windows, updating them as needed
364 WM_int_UpdateWindow(gpWM_RootWindow);
366 // - Draw windows from back to front to the render buffer
367 WM_int_BlitWindow(gpWM_RootWindow);