Usermode/AxWin3 - Clean up unneeded (and silly) log message
[tpg/acess2.git] / Usermode / Applications / axwin3_src / WM / ipc.c
1 /*
2  * Acess2 GUI (AxWin) Version 3
3  * - By John Hodge (thePowersGang)
4  * 
5  * ipc.c
6  * - Interprocess communication
7  */
8 #include <common.h>
9 #include <string.h>
10 #include <ipcmessages.h>
11 #include <stdio.h>
12 #include <wm.h>
13 #include <wm_internals.h>
14 #include <wm_hotkeys.h> // Hotkey registration
15 #include <wm_renderer.h>        // Renderer IPC messages
16 #include <ipc_int.h>
17
18 #define MAX_WINDOWS_PER_APP     128
19
20 // === IMPORTS ===
21 extern tWindow  *gpWM_FocusedWindow;    // Needed for _FocusWindow
22
23 // === PROTOTYPES ===
24 tIPC_Client     *IPC_int_GetClient(const tIPC_Type *IPCType, const void *Ident);
25 void    IPC_int_DropClient(tIPC_Client *Client);
26 void    IPC_Handle(tIPC_Client *Client, size_t MsgLen, tAxWin_IPCMessage *Msg);
27
28 // === GLOBALS ===
29  int    giIPC_ClientCount;
30 tIPC_Client     **gIPC_Clients;
31
32 // === CODE ===
33 // --- Client -> Window Mappings
34 int _CompareClientPtrs(const void *_a, const void *_b)
35 {
36         tIPC_Client     *a = *(tIPC_Client**)_a;
37         tIPC_Client     *b = *(tIPC_Client**)_b;
38
39         ASSERT(a);
40         if(!b)  return -1;
41
42         if(a->IPCType < b->IPCType)     return -1;
43         if(a->IPCType > b->IPCType)     return 1;
44         
45         return a->IPCType->CompareIdent(a->Ident, b->Ident);
46 }
47
48 int IPC_int_BSearchClients(const tIPC_Client *TargetClient, int *Pos)
49 {
50          int    div;
51          int    cmp = -1;
52          int    pos = 0;
53
54         div = giIPC_ClientCount;
55         pos = div/2;
56         while(div > 0)
57         {
58                 div /= 2;
59                 _SysDebug("Cmp with %i [%i] (%p)", pos, div, gIPC_Clients[pos]);
60                 cmp = _CompareClientPtrs(&TargetClient, &gIPC_Clients[pos]);
61 //              _SysDebug("Checking against %i gives %i", pos, cmp);
62                 if(cmp == 0)    break;
63                 if(cmp < 0)
64                         pos -= div;
65                 else
66                         pos += div;
67         }
68         
69         // - Return if found    
70         if(cmp == 0) {
71                 *Pos = pos;
72                 return 1;
73         }
74
75         // Adjust pos to be the index where the new client will be placed
76         if(cmp > 0)     pos ++;
77         *Pos = pos;
78         return 0;
79 }
80
81 tIPC_Client *IPC_int_GetClient(const tIPC_Type *IPCType, const void *Ident)
82 {
83          int    pos = 0;        // Position where the new client will be inserted
84          int    ident_size;
85         tIPC_Client     *ret;
86
87         // - Search list of registered clients
88         if(giIPC_ClientCount > 0)
89         {
90                 tIPC_Client     target;
91                 target.IPCType = IPCType;
92                 target.Ident = Ident;
93                 if( IPC_int_BSearchClients(&target, &pos) )
94                         return gIPC_Clients[pos];
95         }
96
97
98         // - Create a new client entry
99         ident_size = IPCType->GetIdentSize(Ident);
100 //      _SysDebug("ident_size = %i", ident_size);
101         ret = malloc( sizeof(tIPC_Client) + ident_size );
102         if(!ret)        return NULL;
103         ret->IPCType = IPCType;
104         ret->Ident = ret + 1;   // Get the end of the structure
105         memcpy( (void*)ret->Ident, Ident, ident_size );
106         ret->nWindows = 0;
107         ret->Windows = NULL;
108         
109         // TODO: Register some way of detecting the client disconnecting
110         //       > Wait on the thread / register with kernel somehow
111         //       > Sockets are easier, but UDP is harder. Might get rid of it
112
113         // - Insert
114         giIPC_ClientCount ++;
115         gIPC_Clients = realloc(gIPC_Clients, giIPC_ClientCount*sizeof(tIPC_Client*));
116         memmove(&gIPC_Clients[pos+1], &gIPC_Clients[pos], (giIPC_ClientCount-pos-1) * sizeof(tIPC_Client*));
117         gIPC_Clients[pos] = ret;
118
119         return ret;
120 }
121
122 void IPC_int_DropClient(tIPC_Client *Client)
123 {
124         // Remove from client list
125          int    pos;
126         if( !IPC_int_BSearchClients(Client, &pos) ) {
127                 _SysDebug("IPC_int_DropClient: Can't find client %p", Client);
128                 return ;
129         }
130
131         giIPC_ClientCount --;
132         memmove(&gIPC_Clients[pos], &gIPC_Clients[pos+1], (giIPC_ClientCount-pos)*sizeof(tIPC_Client*));
133
134         // Terminate client's windows
135         // - If there were active windows, show an error?
136          int    nWindowsDestroyed = 0;
137         for(int i = 0; i < Client->nWindows; i ++)
138         {
139                 if( Client->Windows[i] )
140                 {
141                         _SysDebug("Window %p:%i %p still exists", Client, i, Client->Windows[i]);
142                         WM_DestroyWindow(Client->Windows[i]);
143                         nWindowsDestroyed ++;
144                 }
145         }
146         if( nWindowsDestroyed )
147         {
148                 _SysDebug("TODO: Show notice that application exited without destroying windows");
149         }
150         
151         // Free client structure
152         free(Client);
153         _SysDebug("Dropped client %p", Client);
154 }
155
156 tWindow *IPC_int_GetWindow(tIPC_Client *Client, uint32_t WindowID)
157 {
158         if( WindowID == -1 )
159                 return NULL;
160
161         if( WindowID >= Client->nWindows ) {
162                 return NULL;
163         }
164
165         return Client->Windows[WindowID];
166 }
167
168 void IPC_int_SetWindow(tIPC_Client *Client, uint32_t WindowID, tWindow *WindowPtr)
169 {
170         if( WindowID >= MAX_WINDOWS_PER_APP )
171                 return ;
172
173         if( WindowID >= Client->nWindows )
174         {
175                  int    oldCount = Client->nWindows;
176                 Client->nWindows = WindowID + 1;
177                 Client->Windows = realloc(Client->Windows, Client->nWindows*sizeof(tWindow*));
178                 memset( &Client->Windows[oldCount],  0, (Client->nWindows-oldCount)*sizeof(tWindow*) );
179                 _SysDebug("Expanded %p's window list from %i to %i", Client, oldCount, Client->nWindows);
180         }
181
182         _SysDebug("Assigned %p to window %i for %p", WindowPtr, WindowID, Client);      
183         Client->Windows[WindowID] = WindowPtr;
184 }
185
186 // --- IPC Message Handlers ---
187 int IPC_Msg_Ping(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
188 {
189         ASSERT(Msg->ID == IPCMSG_PING);
190         
191         if( !(Msg->Flags & IPCMSG_FLAG_RETURN) )        return 0;
192         
193         if( Msg->Size < 4 )     return -1;
194         
195         tIPCMsg_ReturnInt       *ret = (void*)Msg->Data;
196         Msg->ID = IPCMSG_PING;
197         Msg->Size = sizeof(*ret);
198         ret->Value = AXWIN_VERSION;
199         Client->IPCType->SendMessage(Client->Ident, sizeof(*Msg)+sizeof(*ret), Msg);
200         return 0;
201 }
202
203 int IPC_Msg_GetDisplayCount(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
204 {
205         tAxWin_IPCMessage       *ret_hdr;
206         tIPCMsg_ReturnInt       *ret;
207         char    buf[sizeof(*ret_hdr)+sizeof(*ret)];
208         
209         ASSERT(Msg->ID == IPCMSG_GETDISPLAYCOUNT);
210
211         if( !(Msg->Flags & IPCMSG_FLAG_RETURN) )        return 0;
212         
213         ret_hdr = (void*)buf;
214         ret_hdr->ID = IPCMSG_GETDISPLAYCOUNT;
215         ret_hdr->Flags = 0;
216         ret_hdr->Window = -1;
217         ret_hdr->Size = sizeof(*ret);
218         ret = (void*)ret_hdr->Data;
219         ret->Value = 1; // HARD CODE - Current version only supports one display
220         
221         Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);
222         return 0;
223 }
224
225 int IPC_Msg_GetDisplayDims(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
226 {
227         tIPCMsg_GetDisplayDims  *info;
228         tAxWin_IPCMessage       *ret_hdr;
229         tIPCMsg_RetDisplayDims  *ret;
230         char    buf[sizeof(*ret_hdr)+sizeof(*ret)];
231         
232         ASSERT(Msg->ID == IPCMSG_GETDISPLAYDIMS);
233
234         if( !(Msg->Flags & IPCMSG_FLAG_RETURN) )        return 0;
235
236         info = (void*)Msg->Data;        
237
238         ret_hdr = (void*)buf;
239         ret_hdr->ID = IPCMSG_GETDISPLAYDIMS;
240         ret_hdr->Flags = 0;
241         ret_hdr->Window = -1;
242         ret_hdr->Size = sizeof(*ret);
243         ret = (void*)ret_hdr->Data;
244         
245         // HARD CODE! Only one display supported
246         if( info->DisplayID == 0 )
247         {
248                 ret->X = 0;
249                 ret->Y = 0;
250                 ret->W = giScreenWidth;
251                 ret->H = giScreenHeight;
252         }
253         else
254         {
255                 ret->X = 0;     ret->Y = 0;
256                 ret->W = 0;     ret->H = 0;
257         }
258         
259         Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);
260         return 0;
261 }
262
263 int IPC_Msg_SendMsg(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
264 {
265         tIPCMsg_SendMsg *info = (void*)Msg->Data;
266         tWindow *src, *dest;
267
268         ASSERT(Msg->ID == IPCMSG_SENDMSG);
269         
270         // - Sanity checks
271         if( Msg->Size < sizeof(tIPCMsg_SendMsg) )
272                 return -1;
273         if( Msg->Size < sizeof(tIPCMsg_SendMsg) + info->Length )
274                 return -1;
275         
276         src = IPC_int_GetWindow(Client, Msg->Window);
277         if(!src)        return 1;
278         dest = IPC_int_GetWindow(Client, info->Remote);
279         if(!dest)       return 1;
280
281         WM_SendMessage(src, dest, info->ID, info->Length, info->Data);  
282
283         return 0;
284 }
285
286 int IPC_Msg_CreateWin(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
287 {
288         tIPCMsg_CreateWin       *info = (void*)Msg->Data;
289         tWindow *newwin, *parent;
290
291         ASSERT(Msg->ID == IPCMSG_CREATEWIN);
292
293         // - Sanity checks
294         //  > +1 is for NULL byte on string
295         if( Msg->Size < sizeof(*info) + 1 ) {
296                 _SysDebug("IPC_Msg_CreateWin: Size check 1 failed");
297                 return -1;
298         }
299         if( info->Renderer[Msg->Size - sizeof(*info) - 1] != '\0' ) {
300                 _SysDebug("IPC_Msg_CreateWin: Size check 2 failed");
301                 _SysDebug("info = {");
302                 _SysDebug("  .NewWinID = %i", info->NewWinID);
303                 _SysDebug("  .RendererArg = %i", info->RendererArg);
304                 _SysDebug("  .Renderer = '%.*s'", Msg->Size - sizeof(*info), info->Renderer);
305                 _SysDebug("}");
306                 return -1;
307         }
308         
309         // - Get the parent window ID
310         parent = IPC_int_GetWindow(Client, Msg->Window);
311
312         // Catch creating a window with an existing ID
313         if( IPC_int_GetWindow(Client, info->NewWinID) )
314                 return 1;
315
316         // - Create the new window, and save its pointer
317         newwin = WM_CreateWindow(parent, Client, info->NewWinID, info->RendererArg, info->Renderer);
318         IPC_int_SetWindow(Client, info->NewWinID, newwin);
319
320         return 0;
321 }
322
323 int IPC_Msg_DestroyWin(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
324 {
325         tWindow *win;
326         
327         ASSERT(Msg->ID == IPCMSG_DESTROYWIN);
328
329         win = IPC_int_GetWindow(Client, Msg->Window);
330         if( !win )
331                 return 0;
332         
333         WM_DestroyWindow(win);
334         IPC_int_SetWindow(Client, Msg->Window, NULL);
335         return 0;
336 }
337
338 int IPC_Msg_SetWindowTitle(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
339 {
340         tWindow *win;
341
342         ASSERT(Msg->ID == IPCMSG_SETWINTITLE);
343         
344         if( Msg->Size < 1 )     return -1;
345         if( Msg->Data[ Msg->Size-1 ] != '\0' )  return -1;      
346
347         win = IPC_int_GetWindow(Client, Msg->Window);
348         if(!win)        return 1;
349
350         WM_SetWindowTitle(win, Msg->Data);
351
352         return 0;
353 }
354
355 int IPC_Msg_ShowWindow(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
356 {
357         tIPCMsg_Boolean *info = (void*)Msg->Data;
358         tWindow *win;
359         
360         ASSERT(Msg->ID == IPCMSG_SHOWWINDOW);
361         
362         if( Msg->Size < sizeof(*info) ) return -1;
363         
364         win = IPC_int_GetWindow(Client, Msg->Window);
365         if(!win)        return 1;
366
367         WM_ShowWindow(win, !!info->Value);
368         
369         return 0;
370 }
371
372 int IPC_Msg_DecorateWindow(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
373 {
374         tIPCMsg_Boolean *info = (void*)Msg->Data;
375         tWindow *win;
376         
377         if( Msg->Size < sizeof(*info) ) return -1;
378         
379         win = IPC_int_GetWindow(Client, Msg->Window);
380         if(!win)        return 1;
381         
382         WM_DecorateWindow(win, !!info->Value);
383         return 0;
384 }
385
386 int IPC_Msg_FocusWindow(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
387 {
388         tWindow *win;
389
390         ASSERT(Msg->ID == IPCMSG_FOCUSWINDOW);
391         
392         // Don't allow the focus to be changed unless the client has the focus
393 //      if(!gpWM_FocusedWindow) return 1;
394 //      if(gpWM_FocusedWindow->Client != Client)        return 1;
395
396         win = IPC_int_GetWindow(Client, Msg->Window);
397         if(!win)        return 1;
398
399         WM_FocusWindow(win);
400
401         return 0;
402 }
403
404 int IPC_Msg_SetWinPos(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
405 {
406         tIPCMsg_SetWindowPos    *info = (void*)Msg->Data;
407         tWindow *win;
408         
409         ASSERT(Msg->ID == IPCMSG_SETWINPOS);
410         
411         if(Msg->Size < sizeof(*info))   return -1;
412         
413         win = IPC_int_GetWindow(Client, Msg->Window);
414         if(!win)        return 1;
415         
416         _SysDebug("info = {..., bSetPos=%i,bSetDims=%i}", info->bSetPos, info->bSetDims);
417         
418         if(info->bSetPos)
419                 WM_MoveWindow(win, info->X, info->Y);
420         if(info->bSetDims)
421                 WM_ResizeWindow(win, info->W, info->H);
422         
423         return 0;
424 }
425
426 int IPC_Msg_RegisterAction(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
427 {
428         tIPCMsg_RegAction       *info = (void*)Msg->Data;
429         tWindow *win;
430         
431         ASSERT(Msg->ID == IPCMSG_REGACTION);
432
433         if( Msg->Size < sizeof(*info) + 1 )
434                 return -1;
435         
436         win = IPC_int_GetWindow(Client, Msg->Window);
437         if(!win)        return 1;
438
439         if( strnlen(info->Action, Msg->Size - sizeof(*info)) == Msg->Size - sizeof(*info) )
440                 return 1;
441
442         _SysDebug("RegisterAction %p:%i [%i]\"%s\"",
443                 Client, Msg->Window, info->Index, info->Action
444                 );
445
446         WM_Hotkey_RegisterAction(info->Action, win, info->Index);
447
448         return 0;
449 }
450
451 int (*gIPC_MessageHandlers[])(tIPC_Client *Client, tAxWin_IPCMessage *Msg) = {
452         IPC_Msg_Ping,
453         IPC_Msg_GetDisplayCount,
454         IPC_Msg_GetDisplayDims,
455         IPC_Msg_SendMsg,
456         IPC_Msg_CreateWin,
457         IPC_Msg_DestroyWin,     // Destroy window
458         IPC_Msg_SetWindowTitle,
459         IPC_Msg_ShowWindow,
460         IPC_Msg_DecorateWindow,
461         IPC_Msg_FocusWindow,
462         IPC_Msg_SetWinPos,
463         IPC_Msg_RegisterAction
464 };
465 const int giIPC_NumMessageHandlers = sizeof(gIPC_MessageHandlers)/sizeof(gIPC_MessageHandlers[0]);
466
467 void IPC_Handle(tIPC_Client *Client, size_t MsgLen, tAxWin_IPCMessage *Msg)
468 {
469          int    rv = 0;
470         
471 //      _SysDebug("IPC_Handle: (IPCType=%p, Ident=%p, MsgLen=%i, Msg=%p)",
472 //              IPCType, Ident, MsgLen, Msg);
473         
474         if( MsgLen < sizeof(*Msg) ) {
475                 _SysDebug("IPC_Handle: %p Dropped full undersize message (%i < %i)",
476                         Client, MsgLen, sizeof(*Msg));
477                 return ;
478         }
479         if( MsgLen < sizeof(*Msg) + Msg->Size ) {
480                 _SysDebug("IPC_Handle: %p Dropped undersize message (%i < %i+%i)",
481                         Client, MsgLen, sizeof(*Msg), Msg->Size);
482                 return ;
483         }
484         
485         if( Msg->Flags & IPCMSG_FLAG_RENDERER )
486         {
487                 tWindow *win = IPC_int_GetWindow(Client, Msg->Window);
488                 if( !win ) {
489                         _SysDebug("WARNING: NULL window in message %i (%x)", Msg->ID, Msg->Window);
490                         return ;
491                 }
492                 tWMRenderer     *renderer = win->Renderer;
493                 if( Msg->ID >= renderer->nIPCHandlers ) {
494                         _SysDebug("WARNING: Message %i out of range in %s", Msg->ID, renderer->Name);
495                         return ;
496                 }
497                 if( !renderer->IPCHandlers[Msg->ID] ) {
498                         _SysDebug("WARNING: Message %i has no handler in %s", Msg->ID, renderer->Name);
499                         return ;
500                 }
501                 _SysDebug("IPC_Handle: Call %s-%i %ib", renderer->Name, Msg->ID, Msg->Size);
502                 rv = renderer->IPCHandlers[Msg->ID](win, Msg->Size, Msg->Data);
503                 if( rv )
504                         _SysDebug("IPC_Handle: rv != 0 (%i)", rv);
505         }
506         else
507         {
508                 if( Msg->ID >= giIPC_NumMessageHandlers ) {
509                         fprintf(stderr, "WARNING: Unknown message %i (%p)\n", Msg->ID, Client);
510                         _SysDebug("WARNING: Unknown message %i (%p)", Msg->ID, Client);
511                         return ;
512                 }
513                 
514                 if( !gIPC_MessageHandlers[ Msg->ID ] ) {
515                         fprintf(stderr, "WARNING: Message %i does not have a handler\n", Msg->ID);
516                         _SysDebug("WARNING: Message %i does not have a handler", Msg->ID);
517                         return ;
518                 }
519         
520                 _SysDebug("IPC_Handle: Call WM-%i %ib", Msg->ID, Msg->Size);
521                 rv = gIPC_MessageHandlers[Msg->ID](Client, Msg);
522                 if( rv )
523                         _SysDebug("IPC_Handle: rv != 0 (%i)", rv);
524         }
525 }
526
527 // Dispatch a message to the client
528 void IPC_SendWMMessage(tIPC_Client *Client, uint32_t Src, uint32_t Dst, int MsgID, int Len, void *Data)
529 {
530         tAxWin_IPCMessage       *hdr;
531         tIPCMsg_SendMsg         *msg;
532         char    buf[sizeof(*hdr)+sizeof(*msg)+Len];
533         
534         hdr = (void*)buf;
535         msg = (void*)hdr->Data;
536         
537         hdr->ID = IPCMSG_SENDMSG;
538         hdr->Flags = 0;
539         hdr->Size = sizeof(*msg) + Len;
540         hdr->Window = Dst;
541         
542         msg->Remote = Src;
543         msg->ID = MsgID;
544         msg->Length = Len;
545         memcpy(msg->Data, Data, Len);
546         
547         Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);
548 }
549
550 // --- Server->Client replies
551 void IPC_SendReply(tIPC_Client *Client, uint32_t WinID, int MsgID, size_t Len, const void *Data)
552 {
553         tAxWin_IPCMessage       *hdr;
554         char    buf[sizeof(*hdr)+Len];
555         
556         hdr = (void*)buf;
557         
558         hdr->ID = MsgID;
559         hdr->Flags = IPCMSG_FLAG_RENDERER;
560         hdr->Size = Len;
561         hdr->Window = WinID;
562         
563         memcpy(hdr->Data, Data, Len);
564         Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);
565 }
566

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