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

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