Usermode - Working on AxWin3 SubWin widget (also API change for SysSpawn)
[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 #include <decorator.h>
15
16 // === IMPORTS ===
17 extern void     IPC_SendWMMessage(tIPC_Client *Client, uint32_t Src, uint32_t Dst, int Msg, int Len, const void *Data);
18 extern tWindow  *IPC_int_GetWindow(tIPC_Client *Client, uint32_t ID);
19
20 // === GLOBALS ===
21 tWMRenderer     *gpWM_Renderers;
22 tWindow *gpWM_RootWindow;
23 //! Window which will recieve the next keyboard event
24 tWindow *gpWM_FocusedWindow;
25 //! Hilighted window (owner of the currently focused window)
26 tWindow *gpWM_HilightedWindow;
27
28 // === CODE ===
29 void WM_Initialise(void)
30 {
31         WM_CreateWindow(NULL, NULL, 0, 0x0088FF, "Background");
32         gpWM_RootWindow->W = giScreenWidth;
33         gpWM_RootWindow->H = giScreenHeight;
34         gpWM_RootWindow->Flags = WINFLAG_SHOW|WINFLAG_NODECORATE;
35 }
36
37 void WM_RegisterRenderer(tWMRenderer *Renderer)
38 {
39         // TODO: Catch out duplicates
40         Renderer->Next = gpWM_Renderers;
41         gpWM_Renderers = Renderer;
42 }
43
44 // --- Manipulation
45 tWindow *WM_CreateWindow(tWindow *Parent, tIPC_Client *Client, uint32_t ID, int RendererArg, const char *RendererName)
46 {
47         tWMRenderer     *renderer;
48         tWindow *ret;
49         
50         // - Get Renderer
51         for( renderer = gpWM_Renderers; renderer; renderer = renderer->Next )
52         {
53                 if(strcmp(RendererName, renderer->Name) == 0)
54                         break;
55         }
56         if(renderer == NULL)
57                 return NULL;
58
59         // - Call create window function
60         ret = renderer->CreateWindow(RendererArg);
61         ret->Client = Client;
62         ret->ID = ID;
63         ret->Parent = Parent;
64         if(!ret->Parent)
65                 ret->Parent = gpWM_RootWindow;
66         ret->Owner = Parent;
67         ret->Renderer = renderer;
68         ret->Flags |= WINFLAG_CLEAN;    // Needed to stop invaildate early exiting
69
70         // Append to parent
71         if(ret->Parent)
72         {
73                 if(ret->Parent->LastChild)
74                         ret->Parent->LastChild->NextSibling = ret;
75                 else
76                         ret->Parent->FirstChild = ret;
77                 ret->PrevSibling = ret->Parent->LastChild;
78                 ret->Parent->LastChild = ret;
79                 ret->NextSibling = NULL;
80         }
81         else
82         {
83                 gpWM_RootWindow = ret;
84         }
85
86         // Don't decorate child windows by default
87         if(Parent)
88         {
89                 ret->Flags |= WINFLAG_NODECORATE;
90         }
91         
92         // - Return!
93         return ret;
94 }
95
96 tWindow *WM_GetWindowByID(tWindow *Requester, uint32_t ID)
97 {
98         return IPC_int_GetWindow(Requester->Client, ID);
99 }
100
101 tWindow *WM_CreateWindowStruct(size_t ExtraSize)
102 {
103         tWindow *ret;
104         
105         ret = calloc( sizeof(tWindow) + ExtraSize, 1 );
106         ret->RendererInfo = ret + 1;    // Get end of tWindow
107         
108         return ret;
109 }
110
111 void WM_SetWindowTitle(tWindow *Window, const char *Title)
112 {
113         if(Window->Title)
114                 free(Window->Title);
115         Window->Title = strdup(Title);
116         _SysDebug("Window %p title set to '%s'", Window, Title);
117 }
118
119 void WM_RaiseWindow(tWindow *Window)
120 {
121         tWindow *parent = Window->Parent;
122         if(!Window->Parent)     return ;
123         
124         // Remove from list
125         if(Window->PrevSibling)
126                 Window->PrevSibling->NextSibling = Window->NextSibling;
127         if(Window->NextSibling)
128                 Window->NextSibling->PrevSibling = Window->PrevSibling;
129         if(parent->FirstChild == Window)
130                 parent->FirstChild = Window->NextSibling;
131         if(parent->LastChild == Window)
132                 parent->LastChild = Window->PrevSibling;
133
134         // Append to end
135         if(parent->LastChild)
136                 parent->LastChild->NextSibling = Window;
137         else
138                 parent->FirstChild = Window;
139         Window->PrevSibling = parent->LastChild;
140         Window->NextSibling = NULL;
141         parent->LastChild = Window;
142 }
143
144 void WM_FocusWindow(tWindow *Destination)
145 {
146         struct sWndMsg_Bool     _msg;
147         
148         if( gpWM_FocusedWindow == Destination )
149                 return ;
150         if( Destination && !(Destination->Flags & WINFLAG_SHOW) )
151                 return ;
152         
153         _msg.Val = 0;
154         WM_SendMessage(NULL, gpWM_FocusedWindow, WNDMSG_FOCUS, sizeof(_msg), &_msg);
155         _msg.Val = 1;
156         WM_SendMessage(NULL, Destination, WNDMSG_FOCUS, sizeof(_msg), &_msg);
157         
158         WM_Invalidate(gpWM_FocusedWindow);
159         WM_Invalidate(Destination);
160         gpWM_FocusedWindow = Destination;
161
162
163         // Get the owner of the focused window  
164 //      while(Destination && Destination->Owner)        Destination = Destination->Owner;
165 //      gpWM_HilightedWindow = Destination;
166 }
167
168
169 void WM_ShowWindow(tWindow *Window, int bShow)
170 {
171         struct sWndMsg_Bool     _msg;
172         
173         if( !!(Window->Flags & WINFLAG_SHOW) == bShow )
174                 return ;
175
176         // Message window
177         _msg.Val = !!bShow;
178         WM_SendMessage(NULL, Window, WNDMSG_SHOW, sizeof(_msg), &_msg);
179
180         // Update the flag
181         if(bShow)
182                 Window->Flags |= WINFLAG_SHOW;
183         else
184         {
185                 Window->Flags &= ~WINFLAG_SHOW;
186
187                 if( Window == gpWM_FocusedWindow )
188                         WM_FocusWindow(Window->Parent);
189                 
190                 // Just a little memory saving for large hidden windows
191                 if(Window->RenderBuffer) {
192                         free(Window->RenderBuffer);
193                         Window->RenderBuffer = NULL;
194                 }
195         }
196         
197         WM_Invalidate(Window);
198 }
199
200 void WM_DecorateWindow(tWindow *Window, int bDecorate)
201 {
202         if( !(Window->Flags & WINFLAG_NODECORATE) == !!bDecorate )
203                 return ;
204         
205         if(bDecorate)
206                 Window->Flags &= ~WINFLAG_NODECORATE;
207         else
208                 Window->Flags |= WINFLAG_NODECORATE;
209         
210         // Needed because the window size changes
211         if(Window->RenderBuffer) {
212                 free(Window->RenderBuffer);
213                 Window->RenderBuffer = NULL;
214         }
215         
216         WM_Invalidate(Window);
217 }
218
219 int WM_MoveWindow(tWindow *Window, int X, int Y)
220 {
221         // Clip coordinates
222         if(X + Window->W < 0)   X = -Window->W + 1;
223         if(Y + Window->H < 0)   Y = -Window->H + 1;
224         if(X >= giScreenWidth)  X = giScreenWidth - 1;
225         if(Y >= giScreenHeight) Y = giScreenHeight - 1;
226         
227         Window->X = X;  Window->Y = Y;
228
229         WM_Invalidate(Window);
230
231         return 0;
232 }
233
234 int WM_ResizeWindow(tWindow *Window, int W, int H)
235 {
236         if(W <= 0 || H <= 0 )   return 1;
237         if(Window->X + W < 0)   Window->X = -W + 1;
238         if(Window->Y + H < 0)   Window->Y = -H + 1;
239
240         Window->W = W;  Window->H = H;
241
242         if(Window->RenderBuffer) {
243                 free(Window->RenderBuffer);
244                 Window->RenderBuffer = NULL;
245         }
246         WM_Invalidate(Window);
247
248         {
249                 struct sWndMsg_Resize   msg;
250                 msg.W = W;
251                 msg.H = H;
252                 WM_SendMessage(NULL, Window, WNDMSG_RESIZE, sizeof(msg), &msg);
253         }
254         
255         return 0;
256 }
257
258 int WM_SendMessage(tWindow *Source, tWindow *Dest, int Message, int Length, const void *Data)
259 {
260         if(Dest == NULL)        return -2;
261         if(Length > 0 && Data == NULL)  return -1;
262
263         if( Decorator_HandleMessage(Dest, Message, Length, Data) != 1 )
264         {
265                 // TODO: Catch errors from ->HandleMessage
266                 return 0;
267         }
268         
269         // ->HandleMessage returns 1 when the message was not handled
270         if( Dest->Renderer->HandleMessage(Dest, Message, Length, Data) != 1 )
271         {
272                 // TODO: Catch errors from ->HandleMessage
273                 return 0;
274         }
275
276         // TODO: Implement message masking
277
278         if(Dest->Client)
279         {
280                 uint32_t        src_id;
281                 if(!Source)
282                         src_id = -1;
283                 else if(Source->Client != Dest->Client) {
284                         // TODO: Support different client source windows
285                         _SysDebug("WM_SendMessage: TODO - Support inter-client messages");
286                         return -1;
287                 }
288                 else {
289                         src_id = Source->ID;
290                 }
291                 
292                 IPC_SendWMMessage(Dest->Client, src_id, Dest->ID, Message, Length, Data);
293         }       
294
295         return 1;
296 }
297
298 void WM_Invalidate(tWindow *Window)
299 {
300         if(!Window)     return ;
301         _SysDebug("Invalidating %p", Window);
302         // Don't invalidate twice (speedup)
303 //      if( !(Window->Flags & WINFLAG_CLEAN) )  return;
304
305         // Mark for re-render
306         Window->Flags &= ~WINFLAG_CLEAN;
307
308         // Mark up the tree that a child window has changed     
309         while( (Window = Window->Parent) )
310                 Window->Flags &= ~WINFLAG_CHILDCLEAN;
311 }
312
313 // --- Rendering / Update
314 void WM_int_UpdateWindow(tWindow *Window)
315 {
316          int    bDecoratorRedraw = 0;
317
318         // Ignore hidden windows
319         if( !(Window->Flags & WINFLAG_SHOW) )
320                 return ;
321         
322         // Render
323         if( !(Window->Flags & WINFLAG_CLEAN) )
324         {
325                 // Calculate RealW/RealH
326                 if( !(Window->Flags & WINFLAG_NODECORATE) )
327                 {
328                         _SysDebug("Applying decorations to %p", Window);
329                         Decorator_UpdateBorderSize(Window);
330                         Window->RealW = Window->BorderL + Window->W + Window->BorderR;
331                         Window->RealH = Window->BorderT + Window->H + Window->BorderB;
332                         bDecoratorRedraw = 1;
333                 }
334                 else
335                 {
336                         Window->BorderL = 0;
337                         Window->BorderR = 0;
338                         Window->BorderT = 0;
339                         Window->BorderB = 0;
340                         Window->RealW = Window->W;
341                         Window->RealH = Window->H;
342                 }
343                 
344                 Window->Renderer->Redraw(Window);
345                 Window->Flags |= WINFLAG_CLEAN;
346         }
347         
348         // Process children
349         if( !(Window->Flags & WINFLAG_CHILDCLEAN) )
350         {
351                 tWindow *child;
352                 for( child = Window->FirstChild; child; child = child->NextSibling )
353                 {
354                         WM_int_UpdateWindow(child);
355                 }
356                 Window->Flags |= WINFLAG_CHILDCLEAN;
357         }
358         
359         if( bDecoratorRedraw )
360                 Decorator_Redraw(Window);
361 }
362
363 void WM_int_BlitWindow(tWindow *Window)
364 {
365         tWindow *child;
366
367         // Ignore hidden windows
368         if( !(Window->Flags & WINFLAG_SHOW) )
369                 return ;
370
371 //      _SysDebug("Blit %p to (%i,%i) %ix%i", Window, Window->X, Window->Y, Window->RealW, Window->RealH);
372         Video_Blit(Window->RenderBuffer, Window->X, Window->Y, Window->RealW, Window->RealH);
373         
374         if( Window == gpWM_FocusedWindow && Window->CursorW )
375         {
376                 Video_FillRect(
377                         Window->X + Window->BorderL + Window->CursorX,
378                         Window->Y + Window->BorderT + Window->CursorY,
379                         Window->CursorW, Window->CursorH,
380                         0x000000
381                         );
382                         
383         }
384
385         for( child = Window->FirstChild; child; child = child->NextSibling )
386         {
387                 WM_int_BlitWindow(child);
388         }
389 }
390
391 void WM_Update(void)
392 {
393         // Don't redraw if nothing has changed
394         if( (gpWM_RootWindow->Flags & WINFLAG_CHILDCLEAN) )
395                 return ;        
396
397         // - Iterate through visible windows, updating them as needed
398         WM_int_UpdateWindow(gpWM_RootWindow);
399         
400         // - Draw windows from back to front to the render buffer
401         WM_int_BlitWindow(gpWM_RootWindow);
402
403         Video_Update();
404 }
405

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