AcessNative - Better error reporting in NativeFS
[tpg/acess2.git] / Usermode / Applications / axwin3_src / libaxwin3.so_src / wm.c
1 /*
2  * AxWin3 Interface Library
3  * - By John Hodge (thePowersGang)
4  *
5  * wm.c
6  * - Core window management functions
7  */
8 #include <axwin3/axwin.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include "include/internal.h"
12 #include "include/ipc.h"
13 #include <wm_messages.h>
14
15 #define WINDOWS_PER_ALLOC       (64-1)  // -1 to make it 64 pointers (+ Next)
16 #define MAX_HOTKEYS     32
17
18 typedef struct sWindowBlock     tWindowBlock;
19
20 typedef struct sAxWin3_Window   tWindow;
21
22 // === STRUCTURES ===
23 struct sWindowBlock
24 {
25         tWindowBlock    *Next;
26         tWindow *Windows[WINDOWS_PER_ALLOC];
27 };
28
29 // === GLOBALS ===
30  int    giAxWin3_LowestFreeWinID;
31  int    giAxWin3_HighestUsedWinID;
32 tWindowBlock    gAxWin3_WindowList;
33 tAxWin3_HotkeyCallback  gAxWin3_Hotkeys[MAX_HOTKEYS];
34
35 // === CODE ===
36 tWindow *AxWin3_int_CreateWindowStruct(uint32_t ServerID, int ExtraBytes)
37 {
38         tWindow *ret;
39         
40         ret = calloc(sizeof(tWindow) + ExtraBytes, 1);
41         ret->ServerID = ServerID;
42
43         return ret;
44 }
45
46 tWindow *AxWin3_int_GetWindowFromID(uint32_t ServerID)
47 {
48         tWindowBlock    *block = &gAxWin3_WindowList;
49         while(block && ServerID > WINDOWS_PER_ALLOC) {
50                 block = block->Next;
51                 ServerID -= WINDOWS_PER_ALLOC;
52         }
53         if(!block)      return NULL;
54         return block->Windows[ServerID];
55 }
56
57 tWindow *AxWin3_int_AllocateWindowInfo(int DataBytes, int *WinID)
58 {
59          int    idx, newWinID;
60         tWindowBlock *block, *prev = NULL;
61         tWindow *ret;   
62
63         block = &gAxWin3_WindowList;
64         newWinID = giAxWin3_LowestFreeWinID;
65         for( idx = 0; block; newWinID ++ )
66         {
67                 if( block->Windows[idx] == NULL )
68                         break;
69                 idx ++;
70                 if(idx == WINDOWS_PER_ALLOC) {
71                         prev = block;
72                         block = block->Next;
73                         idx = 0;
74                 }
75         }
76         
77         if( !block )
78         {
79                 block = calloc(sizeof(tWindowBlock), 1);
80                 prev->Next = block;
81                 idx = 0;
82         }
83         
84         ret = block->Windows[idx] = AxWin3_int_CreateWindowStruct(newWinID, DataBytes);
85         if(newWinID > giAxWin3_HighestUsedWinID)
86                 giAxWin3_HighestUsedWinID = newWinID;
87         if(newWinID == giAxWin3_LowestFreeWinID)
88                 giAxWin3_HighestUsedWinID ++;
89
90         if(WinID)       *WinID = newWinID;
91
92         return ret;
93 }
94
95 int AxWin3_GetDisplayCount(void)
96 {
97         tAxWin_IPCMessage       *msg;
98         tIPCMsg_ReturnInt       *ret;
99          int    rv;
100         
101         msg = AxWin3_int_AllocateIPCMessage(NULL, IPCMSG_GETDISPLAYCOUNT, IPCMSG_FLAG_RETURN, 0);
102         AxWin3_int_SendIPCMessage(msg);
103         free(msg);      
104
105         msg = AxWin3_int_WaitIPCMessage(IPCMSG_GETDISPLAYCOUNT);
106         if(msg->Size < sizeof(*ret))    return -1;
107         ret = (void*)msg->Data;
108         rv = ret->Value;
109         free(msg);
110         return rv;
111 }
112
113 int AxWin3_GetDisplayDims(int Display, int *X, int *Y, int *Width, int *Height)
114 {
115         tAxWin_IPCMessage       *msg;
116         tIPCMsg_GetDisplayDims  *req;
117         tIPCMsg_RetDisplayDims  *ret;
118         
119         msg = AxWin3_int_AllocateIPCMessage(NULL, IPCMSG_GETDISPLAYDIMS, IPCMSG_FLAG_RETURN, sizeof(*req));
120         req = (void*)msg->Data;
121         req->DisplayID = Display;
122         AxWin3_int_SendIPCMessage(msg);
123         free(msg);
124
125         msg = AxWin3_int_WaitIPCMessage(IPCMSG_GETDISPLAYDIMS);
126         if(msg->Size < sizeof(*ret))    return -1;
127         ret = (void*)msg->Data;
128         
129         if(X)   *X = ret->X;
130         if(Y)   *Y = ret->Y;
131         if(Width)       *Width = ret->W;
132         if(Height)      *Height = ret->H;
133         
134         return 0;
135 }
136
137 tHWND AxWin3_CreateWindow(
138         tHWND Parent, const char *Renderer, int RendererArg,
139         int DataBytes, tAxWin3_WindowMessageHandler MessageHandler
140         )
141 {
142         tWindow *ret;
143          int    newWinID;
144          int    dataSize = sizeof(tIPCMsg_CreateWin) + strlen(Renderer) + 1;
145         tAxWin_IPCMessage       *msg;
146         tIPCMsg_CreateWin       *create_win;
147
148         // Allocate a window ID
149         ret = AxWin3_int_AllocateWindowInfo(DataBytes, &newWinID);
150         if(!ret)        return NULL;
151         ret->Handler = MessageHandler;
152
153         // Create message
154         msg = AxWin3_int_AllocateIPCMessage(Parent, IPCMSG_CREATEWIN, 0, dataSize);
155         create_win = (void*)msg->Data;  
156         create_win->NewWinID = newWinID;
157         create_win->RendererArg = RendererArg;
158         strcpy(create_win->Renderer, Renderer);
159
160         // Send and clean up
161         AxWin3_int_SendIPCMessage(msg);
162         free(msg);
163
164         _SysDebug("AxWin3_CreateWindow: %i :: '%s'", newWinID, Renderer);
165
166         // TODO: Detect and handle possible errors
167
168         // Return success
169         return ret;
170 }
171
172 void AxWin3_DestroyWindow(tHWND Window)
173 {
174         tAxWin_IPCMessage       *msg;
175         
176         msg = AxWin3_int_AllocateIPCMessage(Window, IPCMSG_DESTROYWIN, 0, 0);
177         AxWin3_int_SendIPCMessage(msg);
178         free(msg);
179 }
180
181 void *AxWin3_int_GetDataPtr(tHWND Window)
182 {
183         return Window->Data;
184 }
185
186 int AxWin3_int_DefaultMessageHandler(tWindow *Win, int ID, size_t Len, const void *Data)
187 {
188         switch(ID)
189         {
190         case WNDMSG_HOTKEY: {
191                 const struct sWndMsg_Hotkey *mi = Data;
192                 if( Len < sizeof(*mi) )
193                         return -1;
194
195                 if( mi->ID >= MAX_HOTKEYS ) 
196                         _SysDebug("--- Out of range hotkey %i fired", mi->ID);
197                 else if( gAxWin3_Hotkeys[mi->ID] == 0 )
198                         _SysDebug("--- Unmapped hotkey ID %i fired", mi->ID);
199                 else
200                         gAxWin3_Hotkeys[mi->ID]();
201                 }
202                 return 1;
203         // Honour a close message by default
204         case WNDMSG_CLOSE:
205                 AxWin3_DestroyWindow(Win);
206                 return 1;
207         // Zero fucks given?
208         case WNDMSG_DESTROY:
209                 _SysDebug("TODO: Check that WNDMSG_DESTROY was from us calling _DestroyWindow");
210                 // TODO: Finalise cleanup of window, this will be the last message sent to this window
211                 return 1;
212         default:
213                 return 0;
214         }
215 }
216
217 void AxWin3_int_HandleMessage(tAxWin_IPCMessage *Msg)
218 {
219         tWindow *dest;
220
221         dest = AxWin3_int_GetWindowFromID(Msg->Window);
222
223         switch(Msg->ID)
224         {
225         case IPCMSG_SENDMSG: {
226                 tIPCMsg_SendMsg *info = (void*)Msg->Data;
227                 if(Msg->Size < sizeof(*info) || Msg->Size < sizeof(*info) + info->Length) {
228                         _SysDebug("Message is undersized (%i < %i + %i)",
229                                 Msg->Size < sizeof(*info), info->Length);
230                         return ;
231                 }
232                 if(!dest || !dest->Handler) {
233                         _SysDebug("No handler for destination %p", dest);
234                         return ;
235                 }
236                 _SysDebug("IPC Message 0x%x - %i bytes", info->ID, info->Length);
237
238                 if( dest->Handler(dest, info->ID, info->Length, info->Data) )
239                         ;
240                 else if( AxWin3_int_DefaultMessageHandler(dest, info->ID, info->Length, info->Data) )
241                         ;
242                 else
243                         _SysDebug("--- Unhandled SENDMSG 0x%x win %i", info->ID, Msg->Window);
244                 break; }
245         case IPCMSG_DESTROYWIN:
246                 // Clean up resources associated with this window
247                 break;
248         default:
249                 _SysDebug("Unknow message ID %i", Msg->ID);
250                 break;
251         }
252         
253         free(Msg);
254 }
255
256 void AxWin3_SetWindowTitle(tHWND Window, const char *Title)
257 {
258         tAxWin_IPCMessage       *msg;
259          int    len = strlen(Title);
260         
261         msg = AxWin3_int_AllocateIPCMessage(Window, IPCMSG_SETWINTITLE, 0, len+1);
262         strcpy(msg->Data, Title);
263         
264         AxWin3_int_SendIPCMessage(msg);
265         
266         free(msg);
267 }
268
269 void AxWin3_SendMessage(tHWND Window, tHWND Destination, int Message, int Length, void *Data)
270 {
271         tAxWin_IPCMessage       *msg;
272         tIPCMsg_SendMsg *info;
273         
274         msg = AxWin3_int_AllocateIPCMessage(Window, IPCMSG_SENDMSG, 0, sizeof(*info)+Length);
275         info = (void*)msg->Data;
276         info->Remote = AxWin3_int_GetWindowID(Destination);
277         info->ID = Message;
278         info->Length = Length;
279         memcpy(info->Data, Data, Length);
280         
281         AxWin3_int_SendIPCMessage(msg);
282         free(msg);
283 }
284
285 void *AxWin3_WaitMessage(tHWND Window, int MessageID, size_t *Length)
286 {
287         tAxWin_IPCMessage       *msg;
288         
289         for( ;; )
290         {
291                 msg = AxWin3_int_WaitIPCMessage(IPCMSG_SENDMSG);
292                 if( msg->Window != AxWin3_int_GetWindowID(Window) ) {
293                         AxWin3_int_HandleMessage(msg);
294                         continue ;
295                 }
296                 tIPCMsg_SendMsg *info = (void*)msg->Data;
297                 if( info->ID != MessageID ) {
298                         AxWin3_int_HandleMessage(msg);
299                         continue ;
300                 }
301
302                 *Length = info->Length;
303                 void    *ret = malloc(info->Length);    
304                 memcpy(ret, info->Data, info->Length);
305                 free(msg);
306         
307                 return ret;
308         }
309 }
310
311 void AxWin3_SendIPC(tHWND Window, int Message, size_t Length, const void *Data)
312 {
313         tAxWin_IPCMessage       *msg;
314         
315         msg = AxWin3_int_AllocateIPCMessage(Window, Message, IPCMSG_FLAG_RENDERER, Length);
316         memcpy(msg->Data, Data, Length);
317         AxWin3_int_SendIPCMessage(msg);
318         free(msg);
319 }
320
321 void *AxWin3_WaitIPCMessage(tHWND Window, int MessageID, size_t *Length)
322 {
323         tAxWin_IPCMessage       *msg;
324         for( ;; )
325         {
326                 msg = AxWin3_int_WaitIPCMessage(MessageID);
327                 if( !(msg->Flags & IPCMSG_FLAG_RENDERER) || msg->Window != AxWin3_int_GetWindowID(Window) ) {
328                         AxWin3_int_HandleMessage(msg);
329                         continue ;
330                 }
331
332                 *Length = msg->Size;
333                 void    *ret = malloc(msg->Size);
334                 memcpy(ret, msg->Data, msg->Size);
335                 free(msg);
336         
337                 return ret;
338         }
339 }
340
341 void AxWin3_FocusWindow(tHWND Window)
342 {
343         tAxWin_IPCMessage       *msg;
344         
345         msg = AxWin3_int_AllocateIPCMessage(Window, IPCMSG_FOCUSWINDOW, 0, 0);
346         
347         AxWin3_int_SendIPCMessage(msg);
348         free(msg);
349 }
350
351 void AxWin3_ShowWindow(tHWND Window, int bShow)
352 {
353         tAxWin_IPCMessage       *msg;
354         tIPCMsg_Boolean *info;
355
356         msg = AxWin3_int_AllocateIPCMessage(Window, IPCMSG_SHOWWINDOW, 0, sizeof(*info));
357         info = (void*)msg->Data;
358         info->Value = !!bShow;
359         
360         AxWin3_int_SendIPCMessage(msg);
361         
362         free(msg);
363 }
364
365 void AxWin3_DecorateWindow(tHWND Window, int bDecorate)
366 {
367         tAxWin_IPCMessage       *msg;
368         tIPCMsg_Boolean *info;
369
370         msg = AxWin3_int_AllocateIPCMessage(Window, IPCMSG_DECORATEWINDOW, 0, sizeof(*info));
371         info = (void*)msg->Data;
372         info->Value = !!bDecorate;
373         
374         AxWin3_int_SendIPCMessage(msg);
375         
376         free(msg);
377 }
378
379 void AxWin3_SetWindowPos(tHWND Window, short X, short Y, short W, short H)
380 {
381         tAxWin_IPCMessage       *msg;
382         tIPCMsg_SetWindowPos    *info;
383         
384         msg = AxWin3_int_AllocateIPCMessage(Window, IPCMSG_SETWINPOS, 0, sizeof(*info));
385         info = (void*)msg->Data;
386
387         info->bSetPos = 1;
388         info->bSetDims = 1;
389         info->X = X;    info->Y = Y;
390         info->W = W;    info->H = H;
391
392         AxWin3_int_SendIPCMessage(msg); 
393         free(msg);
394 }
395
396 void AxWin3_MoveWindow(tHWND Window, short X, short Y)
397 {
398         tAxWin_IPCMessage       *msg;
399         tIPCMsg_SetWindowPos    *info;
400         
401         msg = AxWin3_int_AllocateIPCMessage(Window, IPCMSG_SETWINPOS, 0, sizeof(*info));
402         info = (void*)msg->Data;
403
404         info->bSetPos = 1;
405         info->bSetDims = 0;
406         info->X = X;
407         info->Y = Y;
408         
409         AxWin3_int_SendIPCMessage(msg);
410         
411         free(msg);
412 }
413
414 void AxWin3_ResizeWindow(tHWND Window, short W, short H)
415 {
416         tAxWin_IPCMessage       *msg;
417         tIPCMsg_SetWindowPos    *info;
418         
419         msg = AxWin3_int_AllocateIPCMessage(Window, IPCMSG_SETWINPOS, 0, sizeof(*info));
420         info = (void*)msg->Data;
421
422         info->bSetPos = 0;
423         info->bSetDims = 1;
424         info->W = W;
425         info->H = H;
426         
427         AxWin3_int_SendIPCMessage(msg);
428         
429         free(msg);
430 }
431
432 int AxWin3_RegisterAction(tHWND Window, const char *Action, tAxWin3_HotkeyCallback cb)
433 {
434          int    i;
435         for( i = 0; i < MAX_HOTKEYS; i ++ )
436         {
437                 if( gAxWin3_Hotkeys[i] == NULL )
438                 {
439                         tAxWin_IPCMessage       *msg;
440                         struct sIPCMsg_RegAction        *info;
441                         gAxWin3_Hotkeys[i] = cb;
442                         
443                         msg = AxWin3_int_AllocateIPCMessage(Window, IPCMSG_REGACTION, 0, sizeof(*info)+strlen(Action)+1);
444                         info = (void*)msg->Data;
445                 
446                         info->Index = i;
447                         strcpy(info->Action, Action);
448                         
449                         AxWin3_int_SendIPCMessage(msg);
450                         free(msg);
451                         return i;
452                 }
453         }
454         return -1;
455 }
456

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