38bbbf34cfea84c09e470a849012b59e30cc773f
[tpg/acess2.git] / Usermode / Applications / axwin3_src / WM / wm.c
1 /*
2  * Acess2 Window Manager v3
3  * - By John Hodge (thePowersGang)
4  *
5  * wm.c
6  * - Window manager core
7  */
8 #include <common.h>
9 #include <wm_renderer.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <video.h>
13 #include <wm_messages.h>
14
15 // === IMPORTS ===
16 extern void     IPC_SendWMMessage(tIPC_Client *Client, uint32_t Src, uint32_t Dst, int Msg, int Len, void *Data);
17
18 // === GLOBALS ===
19 tWMRenderer     *gpWM_Renderers;
20 tWindow *gpWM_RootWindow;
21
22 // === CODE ===
23 void WM_Initialise(void)
24 {
25         WM_CreateWindow(NULL, NULL, 0, 0x0088FF, "Background");
26         gpWM_RootWindow->W = giScreenWidth;
27         gpWM_RootWindow->H = giScreenHeight;
28         gpWM_RootWindow->Flags = WINFLAG_SHOW;
29 }
30
31 void WM_RegisterRenderer(tWMRenderer *Renderer)
32 {
33         // TODO: Catch out duplicates
34         Renderer->Next = gpWM_Renderers;
35         gpWM_Renderers = Renderer;
36 }
37
38 // --- Manipulation
39 tWindow *WM_CreateWindow(tWindow *Parent, tIPC_Client *Client, uint32_t ID, int RendererArg, const char *RendererName)
40 {
41         tWMRenderer     *renderer;
42         tWindow *ret;
43         
44         // - Get Renderer
45         for( renderer = gpWM_Renderers; renderer; renderer = renderer->Next )
46         {
47                 if(strcmp(RendererName, renderer->Name) == 0)
48                         break;
49         }
50         if(renderer == NULL)
51                 return NULL;
52
53         if(!Parent)
54                 Parent = gpWM_RootWindow;
55
56         // - Call create window function
57         ret = renderer->CreateWindow(RendererArg);
58         ret->Client = Client;
59         ret->ID = ID;
60         ret->Parent = Parent;
61         ret->Renderer = renderer;
62         ret->Flags = WINFLAG_CLEAN;     // Needed to stop invaildate early exiting
63
64         // Append to parent
65         if(Parent)
66         {
67                 if(Parent->LastChild)
68                         Parent->LastChild->NextSibling = ret;
69                 else
70                         Parent->FirstChild = ret;
71                 ret->PrevSibling = Parent->LastChild;
72                 Parent->LastChild = ret;
73                 ret->NextSibling = NULL;
74         }
75         else
76         {
77                 gpWM_RootWindow = ret;
78         }
79
80         // - Return!
81         return ret;
82 }
83
84 tWindow *WM_CreateWindowStruct(size_t ExtraSize)
85 {
86         tWindow *ret;
87         
88         ret = calloc( sizeof(tWindow) + ExtraSize, 1 );
89         ret->RendererInfo = ret + 1;    // Get end of tWindow
90         
91         return ret;
92 }
93
94 void WM_RaiseWindow(tWindow *Window)
95 {
96         tWindow *parent = Window->Parent;
97         if(!Window->Parent)     return ;
98         
99         // Remove from list
100         if(Window->PrevSibling)
101                 Window->PrevSibling->NextSibling = Window->NextSibling;
102         if(Window->NextSibling)
103                 Window->NextSibling->PrevSibling = Window->PrevSibling;
104         if(parent->FirstChild == Window)
105                 parent->FirstChild = Window->NextSibling;
106         if(parent->LastChild == Window)
107                 parent->LastChild = Window->PrevSibling;
108
109         // Append to end
110         if(parent->LastChild)
111                 parent->LastChild->NextSibling = Window;
112         else
113                 parent->FirstChild = Window;
114         Window->PrevSibling = parent->LastChild;
115         Window->NextSibling = NULL;
116         parent->LastChild = Window;
117 }
118
119 void WM_ShowWindow(tWindow *Window, int bShow)
120 {
121         // Message window
122         struct sWndMsg_Bool     _msg;
123         
124         _msg.Val = !!bShow;
125         WM_SendMessage(NULL, Window, WNDMSG_SHOW, sizeof(_msg), &_msg);
126         
127         if(bShow)
128                 Window->Flags |= WINFLAG_SHOW;
129         else
130                 Window->Flags &= ~WINFLAG_SHOW;
131         WM_Invalidate(Window);
132 }
133
134 int WM_MoveWindow(tWindow *Window, int X, int Y)
135 {
136         // Clip coordinates
137         if(X + Window->W < 0)   X = -Window->W + 1;
138         if(Y + Window->H < 0)   Y = -Window->H + 1;
139         if(X >= giScreenWidth)  X = giScreenWidth - 1;
140         if(Y >= giScreenHeight) Y = giScreenHeight - 1;
141         
142         Window->X = X;  Window->Y = Y;
143
144         WM_Invalidate(Window);
145
146         return 0;
147 }
148
149 int WM_ResizeWindow(tWindow *Window, int W, int H)
150 {
151         if(W <= 0 || H <= 0 )   return 1;
152         if(Window->X + W < 0)   Window->X = -W + 1;
153         if(Window->Y + H < 0)   Window->Y = -H + 1;
154         
155         Window->W = W;  Window->H = H;
156
157         WM_Invalidate(Window);
158
159         {
160                 struct sWndMsg_Resize   msg;
161                 msg.W = W;
162                 msg.H = H;
163                 WM_SendMessage(NULL, Window, WNDMSG_RESIZE, sizeof(msg), &msg);
164         }
165         
166         return 0;
167 }
168
169 int WM_SendMessage(tWindow *Source, tWindow *Dest, int Message, int Length, void *Data)
170 {
171         if(Dest == NULL)        return -2;
172         if(Length > 0 && Data == NULL)  return -1;
173         
174         // ->HandleMessage returns 1 when the message was not handled
175         if( Dest->Renderer->HandleMessage(Dest, Message, Length, Data) != 1 )
176         {
177                 // TODO: Catch errors from ->HandleMessage
178                 return 0;
179         }
180
181         // TODO: Implement message masking
182
183         if(Dest->Client)
184         {
185                 uint32_t        src_id;
186                 if(!Source)
187                         src_id = -1;
188                 else if(Source->Client != Dest->Client) {
189                         // TODO: Support different client source windows
190                         _SysDebug("WM_SendMessage: TODO - Support inter-client messages");
191                         return -1;
192                 }
193                 else {
194                         src_id = Source->ID;
195                 }
196                 
197                 IPC_SendWMMessage(Dest->Client, src_id, Dest->ID, Message, Length, Data);
198         }       
199
200         return 1;
201 }
202
203 void WM_Invalidate(tWindow *Window)
204 {
205         _SysDebug("Invalidating %p", Window);
206         // Don't invalidate twice (speedup)
207 //      if( !(Window->Flags & WINFLAG_CLEAN) )  return;
208
209         // Mark for re-render
210         Window->Flags &= ~WINFLAG_CLEAN;
211
212         // Mark up the tree that a child window has changed     
213         while( (Window = Window->Parent) )
214                 Window->Flags &= ~WINFLAG_CHILDCLEAN;
215 }
216
217 // --- Rendering / Update
218 void WM_int_UpdateWindow(tWindow *Window)
219 {
220         tWindow *child;
221
222         // Ignore hidden windows
223         if( !(Window->Flags & WINFLAG_SHOW) )
224                 return ;
225         
226         // Render
227         if( !(Window->Flags & WINFLAG_CLEAN) )
228         {
229                 Window->Renderer->Redraw(Window);
230                 Window->Flags |= WINFLAG_CLEAN;
231         }
232         
233         // Process children
234         if( !(Window->Flags & WINFLAG_CHILDCLEAN) )
235         {
236                 for( child = Window->FirstChild; child; child = child->NextSibling )
237                 {
238                         WM_int_UpdateWindow(child);
239                 }
240                 Window->Flags |= WINFLAG_CHILDCLEAN;
241         }
242         
243 }
244
245 void WM_int_BlitWindow(tWindow *Window)
246 {
247         tWindow *child;
248
249         // Ignore hidden windows
250         if( !(Window->Flags & WINFLAG_SHOW) )
251                 return ;
252
253         _SysDebug("Blit %p to (%i,%i) %ix%i", Window, Window->X, Window->Y, Window->W, Window->H);
254         Video_Blit(Window->RenderBuffer, Window->X, Window->Y, Window->W, Window->H);
255         
256         for( child = Window->FirstChild; child; child = child->NextSibling )
257         {
258                 WM_int_BlitWindow(child);
259         }
260 }
261
262 void WM_Update(void)
263 {
264         // Don't redraw if nothing has changed
265         if( (gpWM_RootWindow->Flags & WINFLAG_CHILDCLEAN) )
266                 return ;        
267
268         // - Iterate through visible windows, updating them as needed
269         WM_int_UpdateWindow(gpWM_RootWindow);
270         
271         // - Draw windows from back to front to the render buffer
272         WM_int_BlitWindow(gpWM_RootWindow);
273
274         Video_Update();
275 }
276

UCC git Repository :: git.ucc.asn.au