bfa86b10720608140094b8a1455e27d2e768d9fe
[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         }
74         else
75         {
76                 gpWM_RootWindow = ret;
77         }
78
79         // - Return!
80         return ret;
81 }
82
83 tWindow *WM_CreateWindowStruct(size_t ExtraSize)
84 {
85         tWindow *ret;
86         
87         ret = calloc( sizeof(tWindow) + ExtraSize, 1 );
88         ret->RendererInfo = ret + 1;    // Get end of tWindow
89         
90         return ret;
91 }
92
93 void WM_ShowWindow(tWindow *Window, int bShow)
94 {
95         // TODO: Message window
96         if(bShow)
97                 Window->Flags |= WINFLAG_SHOW;
98         else
99                 Window->Flags &= ~WINFLAG_SHOW;
100         WM_Invalidate(Window);
101 }
102
103 int WM_MoveWindow(tWindow *Window, int X, int Y)
104 {
105         // Clip coordinates
106         if(X + Window->W < 0)   X = -Window->W + 1;
107         if(Y + Window->H < 0)   Y = -Window->H + 1;
108         if(X >= giScreenWidth)  X = giScreenWidth - 1;
109         if(Y >= giScreenHeight) Y = giScreenHeight - 1;
110         
111         Window->X = X;  Window->Y = Y;
112
113         WM_Invalidate(Window);
114
115         return 0;
116 }
117
118 int WM_ResizeWindow(tWindow *Window, int W, int H)
119 {
120         if(W <= 0 || H <= 0 )   return 1;
121         if(Window->X + W < 0)   Window->X = -W + 1;
122         if(Window->Y + H < 0)   Window->Y = -H + 1;
123         
124         Window->W = W;  Window->H = H;
125
126         WM_Invalidate(Window);
127
128         {
129                 struct sWndMsg_Resize   msg;
130                 msg.W = W;
131                 msg.H = H;
132                 WM_SendMessage(NULL, Window, WNDMSG_RESIZE, sizeof(msg), &msg);
133         }
134         
135         return 0;
136 }
137
138 int WM_SendMessage(tWindow *Source, tWindow *Dest, int Message, int Length, void *Data)
139 {
140         if(Dest == NULL)        return -2;
141         if(Length > 0 && Data == NULL)  return -1;
142         
143         // ->HandleMessage returns 1 when the message was not handled
144         if( Dest->Renderer->HandleMessage(Dest, Message, Length, Data) != 1 )
145         {
146                 // TODO: Catch errors from ->HandleMessage
147                 return 0;
148         }
149
150         // TODO: Implement message masking
151
152         if(Dest->Client)
153         {
154                 uint32_t        src_id;
155                 if(!Source)
156                         src_id = -1;
157                 else if(Source->Client != Dest->Client) {
158                         // TODO: Support different client source windows
159                         _SysDebug("WM_SendMessage: TODO - Support inter-client messages");
160                         return -1;
161                 }
162                 else {
163                         src_id = Source->ID;
164                 }
165                 
166                 IPC_SendWMMessage(Dest->Client, src_id, Dest->ID, Message, Length, Data);
167         }       
168
169         return 1;
170 }
171
172 void WM_Invalidate(tWindow *Window)
173 {
174         // Don't invalidate twice (speedup)
175         if( !(Window->Flags & WINFLAG_CLEAN) )  return;
176
177         // Mark for re-render
178         Window->Flags &= ~WINFLAG_CLEAN;
179
180         // Mark up the tree that a child window has changed     
181         while( (Window = Window->Parent) )
182                 Window->Flags &= ~WINFLAG_CHILDCLEAN;
183 }
184
185 // --- Rendering / Update
186 void WM_int_UpdateWindow(tWindow *Window)
187 {
188         tWindow *child;
189
190         // Ignore hidden windows
191         if( !(Window->Flags & WINFLAG_SHOW) )
192                 return ;
193         
194         // Render
195         if( !(Window->Flags & WINFLAG_CLEAN) )
196         {
197                 Window->Renderer->Redraw(Window);
198                 Window->Flags |= WINFLAG_CLEAN;
199         }
200         
201         // Process children
202         if( !(Window->Flags & WINFLAG_CHILDCLEAN) )
203         {
204                 for( child = Window->FirstChild; child; child = child->NextSibling )
205                 {
206                         WM_int_UpdateWindow(child);
207                 }
208                 Window->Flags |= WINFLAG_CHILDCLEAN;
209         }
210         
211 }
212
213 void WM_int_BlitWindow(tWindow *Window)
214 {
215         tWindow *child;
216
217         // Ignore hidden windows
218         if( !(Window->Flags & WINFLAG_SHOW) )
219                 return ;
220         
221         Video_Blit(Window->RenderBuffer, Window->X, Window->Y, Window->W, Window->H);
222         
223         for( child = Window->FirstChild; child; child = child->NextSibling )
224         {
225                 WM_int_BlitWindow(child);
226         }
227 }
228
229 void WM_Update(void)
230 {
231         // Don't redraw if nothing has changed
232         if( (gpWM_RootWindow->Flags & WINFLAG_CHILDCLEAN) )
233                 return ;        
234
235         // - Iterate through visible windows, updating them as needed
236         WM_int_UpdateWindow(gpWM_RootWindow);
237         
238         // - Draw windows from back to front to the render buffer
239         WM_int_BlitWindow(gpWM_RootWindow);
240
241         Video_Update();
242 }
243

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