2 * Acess2 GUI (AxWin) Version 3
3 * - By John Hodge (thePowersGang)
6 * - Interprocess communication
10 #include <ipcmessages.h>
13 #include <wm_internals.h>
14 #include <wm_hotkeys.h> // Hotkey registration
15 #include <wm_renderer.h> // Renderer IPC messages
18 #define MAX_WINDOWS_PER_APP 128
21 extern tWindow *gpWM_FocusedWindow; // Needed for _FocusWindow
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);
29 int giIPC_ClientCount;
30 tIPC_Client **gIPC_Clients;
33 // --- Client -> Window Mappings
34 int _CompareClientPtrs(const void *_a, const void *_b)
36 tIPC_Client *a = *(tIPC_Client**)_a;
37 tIPC_Client *b = *(tIPC_Client**)_b;
42 if(a->IPCType < b->IPCType) return -1;
43 if(a->IPCType > b->IPCType) return 1;
45 return a->IPCType->CompareIdent(a->Ident, b->Ident);
48 int IPC_int_BSearchClients(const tIPC_Client *TargetClient, int *Pos)
54 div = giIPC_ClientCount;
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);
75 // Adjust pos to be the index where the new client will be placed
81 tIPC_Client *IPC_int_GetClient(const tIPC_Type *IPCType, const void *Ident)
83 int pos = 0; // Position where the new client will be inserted
87 // - Search list of registered clients
88 if(giIPC_ClientCount > 0)
91 target.IPCType = IPCType;
93 if( IPC_int_BSearchClients(&target, &pos) )
94 return gIPC_Clients[pos];
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 );
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
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;
122 void IPC_int_DropClient(tIPC_Client *Client)
124 // Remove from client list
126 if( !IPC_int_BSearchClients(Client, &pos) ) {
127 _SysDebug("IPC_int_DropClient: Can't find client %p", Client);
131 giIPC_ClientCount --;
132 memmove(&gIPC_Clients[pos], &gIPC_Clients[pos+1], (giIPC_ClientCount-pos)*sizeof(tIPC_Client*));
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 ++)
139 if( Client->Windows[i] )
141 _SysDebug("Window %p:%i %p still exists", Client, i, Client->Windows[i]);
142 WM_DestroyWindow(Client->Windows[i]);
143 nWindowsDestroyed ++;
146 if( nWindowsDestroyed )
148 _SysDebug("TODO: Show notice that application exited without destroying windows");
151 // Free client structure
153 _SysDebug("Dropped client %p", Client);
156 tWindow *IPC_int_GetWindow(tIPC_Client *Client, uint32_t WindowID)
161 if( WindowID >= Client->nWindows ) {
165 return Client->Windows[WindowID];
168 void IPC_int_SetWindow(tIPC_Client *Client, uint32_t WindowID, tWindow *WindowPtr)
170 if( WindowID >= MAX_WINDOWS_PER_APP )
173 if( WindowID >= Client->nWindows )
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);
182 _SysDebug("Assigned %p to window %i for %p", WindowPtr, WindowID, Client);
183 Client->Windows[WindowID] = WindowPtr;
186 // --- IPC Message Handlers ---
187 int IPC_Msg_Ping(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
189 ASSERT(Msg->ID == IPCMSG_PING);
191 if( !(Msg->Flags & IPCMSG_FLAG_RETURN) ) return 0;
193 if( Msg->Size < 4 ) return -1;
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);
203 int IPC_Msg_GetDisplayCount(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
205 tAxWin_IPCMessage *ret_hdr;
206 tIPCMsg_ReturnInt *ret;
207 char buf[sizeof(*ret_hdr)+sizeof(*ret)];
209 ASSERT(Msg->ID == IPCMSG_GETDISPLAYCOUNT);
211 if( !(Msg->Flags & IPCMSG_FLAG_RETURN) ) return 0;
213 ret_hdr = (void*)buf;
214 ret_hdr->ID = IPCMSG_GETDISPLAYCOUNT;
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
221 Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);
225 int IPC_Msg_GetDisplayDims(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
227 tIPCMsg_GetDisplayDims *info;
228 tAxWin_IPCMessage *ret_hdr;
229 tIPCMsg_RetDisplayDims *ret;
230 char buf[sizeof(*ret_hdr)+sizeof(*ret)];
232 ASSERT(Msg->ID == IPCMSG_GETDISPLAYDIMS);
234 if( !(Msg->Flags & IPCMSG_FLAG_RETURN) ) return 0;
236 info = (void*)Msg->Data;
238 ret_hdr = (void*)buf;
239 ret_hdr->ID = IPCMSG_GETDISPLAYDIMS;
241 ret_hdr->Window = -1;
242 ret_hdr->Size = sizeof(*ret);
243 ret = (void*)ret_hdr->Data;
245 // HARD CODE! Only one display supported
246 if( info->DisplayID == 0 )
250 ret->W = giScreenWidth;
251 ret->H = giScreenHeight;
255 ret->X = 0; ret->Y = 0;
256 ret->W = 0; ret->H = 0;
259 Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);
263 int IPC_Msg_SendMsg(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
265 tIPCMsg_SendMsg *info = (void*)Msg->Data;
268 ASSERT(Msg->ID == IPCMSG_SENDMSG);
271 if( Msg->Size < sizeof(tIPCMsg_SendMsg) )
273 if( Msg->Size < sizeof(tIPCMsg_SendMsg) + info->Length )
276 src = IPC_int_GetWindow(Client, Msg->Window);
278 dest = IPC_int_GetWindow(Client, info->Remote);
281 WM_SendMessage(src, dest, info->ID, info->Length, info->Data);
286 int IPC_Msg_CreateWin(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
288 tIPCMsg_CreateWin *info = (void*)Msg->Data;
289 tWindow *newwin, *parent;
291 ASSERT(Msg->ID == IPCMSG_CREATEWIN);
294 // > +1 is for NULL byte on string
295 if( Msg->Size < sizeof(*info) + 1 ) {
296 _SysDebug("IPC_Msg_CreateWin: Size check 1 failed");
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);
309 // - Get the parent window ID
310 parent = IPC_int_GetWindow(Client, Msg->Window);
312 // Catch creating a window with an existing ID
313 if( IPC_int_GetWindow(Client, info->NewWinID) )
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);
323 int IPC_Msg_DestroyWin(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
327 ASSERT(Msg->ID == IPCMSG_DESTROYWIN);
329 win = IPC_int_GetWindow(Client, Msg->Window);
333 WM_DestroyWindow(win);
334 IPC_int_SetWindow(Client, Msg->Window, NULL);
338 int IPC_Msg_SetWindowTitle(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
342 ASSERT(Msg->ID == IPCMSG_SETWINTITLE);
344 if( Msg->Size < 1 ) return -1;
345 if( Msg->Data[ Msg->Size-1 ] != '\0' ) return -1;
347 win = IPC_int_GetWindow(Client, Msg->Window);
350 WM_SetWindowTitle(win, Msg->Data);
355 int IPC_Msg_ShowWindow(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
357 tIPCMsg_Boolean *info = (void*)Msg->Data;
360 ASSERT(Msg->ID == IPCMSG_SHOWWINDOW);
362 if( Msg->Size < sizeof(*info) ) return -1;
364 win = IPC_int_GetWindow(Client, Msg->Window);
367 WM_ShowWindow(win, !!info->Value);
372 int IPC_Msg_DecorateWindow(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
374 tIPCMsg_Boolean *info = (void*)Msg->Data;
377 if( Msg->Size < sizeof(*info) ) return -1;
379 win = IPC_int_GetWindow(Client, Msg->Window);
382 WM_DecorateWindow(win, !!info->Value);
386 int IPC_Msg_FocusWindow(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
390 ASSERT(Msg->ID == IPCMSG_FOCUSWINDOW);
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;
396 win = IPC_int_GetWindow(Client, Msg->Window);
404 int IPC_Msg_SetWinPos(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
406 tIPCMsg_SetWindowPos *info = (void*)Msg->Data;
409 ASSERT(Msg->ID == IPCMSG_SETWINPOS);
411 if(Msg->Size < sizeof(*info)) return -1;
413 win = IPC_int_GetWindow(Client, Msg->Window);
416 _SysDebug("info = {..., bSetPos=%i,bSetDims=%i}", info->bSetPos, info->bSetDims);
419 WM_MoveWindow(win, info->X, info->Y);
421 WM_ResizeWindow(win, info->W, info->H);
426 int IPC_Msg_RegisterAction(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
428 tIPCMsg_RegAction *info = (void*)Msg->Data;
431 ASSERT(Msg->ID == IPCMSG_REGACTION);
433 if( Msg->Size < sizeof(*info) + 1 )
436 win = IPC_int_GetWindow(Client, Msg->Window);
439 if( strnlen(info->Action, Msg->Size - sizeof(*info)) == Msg->Size - sizeof(*info) )
442 _SysDebug("RegisterAction %p:%i [%i]\"%s\"",
443 Client, Msg->Window, info->Index, info->Action
446 WM_Hotkey_RegisterAction(info->Action, win, info->Index);
451 int (*gIPC_MessageHandlers[])(tIPC_Client *Client, tAxWin_IPCMessage *Msg) = {
453 IPC_Msg_GetDisplayCount,
454 IPC_Msg_GetDisplayDims,
457 IPC_Msg_DestroyWin, // Destroy window
458 IPC_Msg_SetWindowTitle,
460 IPC_Msg_DecorateWindow,
463 IPC_Msg_RegisterAction
465 const int giIPC_NumMessageHandlers = sizeof(gIPC_MessageHandlers)/sizeof(gIPC_MessageHandlers[0]);
467 void IPC_Handle(tIPC_Client *Client, size_t MsgLen, tAxWin_IPCMessage *Msg)
471 // _SysDebug("IPC_Handle: (IPCType=%p, Ident=%p, MsgLen=%i, Msg=%p)",
472 // IPCType, Ident, MsgLen, Msg);
474 if( MsgLen < sizeof(tAxWin_IPCMessage) )
476 if( MsgLen < sizeof(tAxWin_IPCMessage) + Msg->Size )
479 if( Msg->Flags & IPCMSG_FLAG_RENDERER )
481 tWindow *win = IPC_int_GetWindow(Client, Msg->Window);
483 _SysDebug("WARNING: NULL window in message %i (%x)", Msg->ID, Msg->Window);
486 tWMRenderer *renderer = win->Renderer;
487 if( Msg->ID >= renderer->nIPCHandlers ) {
488 _SysDebug("WARNING: Message %i out of range in %s", Msg->ID, renderer->Name);
491 if( !renderer->IPCHandlers[Msg->ID] ) {
492 _SysDebug("WARNING: Message %i has no handler in %s", Msg->ID, renderer->Name);
495 _SysDebug("IPC_Handle: Call %s-%i", renderer->Name, Msg->ID);
496 rv = renderer->IPCHandlers[Msg->ID](win, Msg->Size, Msg->Data);
498 _SysDebug("IPC_Handle: rv != 0 (%i)", rv);
502 if( Msg->ID >= giIPC_NumMessageHandlers ) {
503 fprintf(stderr, "WARNING: Unknown message %i (%p)\n", Msg->ID, Client);
504 _SysDebug("WARNING: Unknown message %i (%p)", Msg->ID, Client);
508 if( !gIPC_MessageHandlers[ Msg->ID ] ) {
509 fprintf(stderr, "WARNING: Message %i does not have a handler\n", Msg->ID);
510 _SysDebug("WARNING: Message %i does not have a handler", Msg->ID);
514 _SysDebug("IPC_Handle: Call WM-%i", Msg->ID);
515 rv = gIPC_MessageHandlers[Msg->ID](Client, Msg);
517 _SysDebug("IPC_Handle: rv != 0 (%i)", rv);
521 // Dispatch a message to the client
522 void IPC_SendWMMessage(tIPC_Client *Client, uint32_t Src, uint32_t Dst, int MsgID, int Len, void *Data)
524 tAxWin_IPCMessage *hdr;
525 tIPCMsg_SendMsg *msg;
526 char buf[sizeof(*hdr)+sizeof(*msg)+Len];
529 msg = (void*)hdr->Data;
531 hdr->ID = IPCMSG_SENDMSG;
533 hdr->Size = sizeof(*msg) + Len;
539 memcpy(msg->Data, Data, Len);
541 Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);
544 // --- Server->Client replies
545 void IPC_SendReply(tIPC_Client *Client, uint32_t WinID, int MsgID, size_t Len, const void *Data)
547 tAxWin_IPCMessage *hdr;
548 char buf[sizeof(*hdr)+Len];
553 hdr->Flags = IPCMSG_FLAG_RENDERER;
557 memcpy(hdr->Data, Data, Len);
558 Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);