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

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