2 * AxWin4 Interface Library
3 * - By John Hodge (thePowersGang)
8 #include <axwin4/axwin.h>
9 #include "include/common.hpp"
10 #include "include/IIPCChannel.hpp"
11 #include "include/CIPCChannel_AcessIPCPipe.hpp"
12 #include <ipc_proto.hpp>
22 IIPCChannel* gIPCChannel;
23 ::std::mutex glSyncReply;
24 bool gSyncReplyActive;
26 CDeserialiser gSyncReplyBuf;
28 extern "C" bool AxWin4_Connect(const char *URI)
30 _SysDebug("AxWin4_Connect('%s')", URI);
35 if( strncmp(URI, "ipcpipe://", 3+4+3) == 0 )
37 gIPCChannel = new CIPCChannel_AcessIPCPipe(URI+3+4+3);
41 _SysDebug("Unknown protocol");
45 catch( const ::std::exception& e )
47 fprintf(stderr, "AxWin4_Connect: %s\n", e.what());
53 extern "C" bool AxWin4_PeekEventQueue(void)
58 extern "C" bool AxWin4_WaitEventQueue(uint64_t Timeout)
60 return AxWin4_WaitEventQueueSelect(0, NULL, NULL, NULL, Timeout);
63 extern "C" bool AxWin4_WaitEventQueueSelect(int nFDs, fd_set *rfds, fd_set *wfds, fd_set *efds, uint64_t Timeout)
71 int64_t select_timeout = Timeout;
72 int64_t *select_timeout_p = (Timeout ? &select_timeout : 0);
74 nFDs = ::std::max(nFDs, gIPCChannel->FillSelect(*rfds));
75 _SysSelect(nFDs, rfds, wfds, efds, select_timeout_p, 0);
76 return gIPCChannel->HandleSelect(*rfds);
79 void SendMessage(CSerialiser& message)
81 gIPCChannel->Send(message);
83 void RecvMessage(CDeserialiser& message)
85 uint8_t id = message.ReadU8();
86 _SysDebug("RecvMessage: id=%i", id);
90 // If we hear ping, we must pong
93 pong.WriteU8(IPCMSG_REPLY);
94 pong.WriteU8(IPCMSG_PING);
99 // Flag reply and take a copy of this message
100 if( !gSyncReplyActive )
102 _SysDebug("Unexpected reply message %i", message.ReadU8());
104 else if( gSyncReplyValid )
106 // Oh... that was unexpected
107 _SysDebug("Unexpected second reply message %i", message.ReadU8());
111 gSyncReplyValid = true;
112 gSyncReplyBuf = message;
115 // TODO: Handle messages from server (input events, IPC)
116 // TODO: If an event is currently being processed, save the message in a queue to be handled when processing is complete
117 // - This will prevent deep recursion (and make server errors aparent)
118 case IPCMSG_INPUTEVENT:
119 _SysDebug("TODO: Input events");
122 _SysDebug("TODO: RecvMessage(%i)", id);
127 CDeserialiser GetSyncReply(CSerialiser& request, unsigned int Message)
129 ::std::lock_guard<std::mutex> lock(glSyncReply);
130 gSyncReplyActive = true;
131 gSyncReplyValid = false;
132 // Send once lock is acquired
133 SendMessage(request);
135 while( !gSyncReplyValid )
138 if( !AxWin4_WaitEventQueue(0) )
139 throw ::std::runtime_error("Connection dropped while waiting for reply");
141 gSyncReplyActive = false;
143 uint8_t id = gSyncReplyBuf.ReadU8();
146 _SysDebug("Unexpected reply message id=%i, expected %i",
148 throw ::std::runtime_error("Sequencing error, unexpected reply");
151 // Use move to avoid copying
152 return ::std::move(gSyncReplyBuf);
155 extern "C" void AxWin4_GetScreenDimensions(unsigned int ScreenIndex, unsigned int *Width, unsigned int *Height)
158 req.WriteU8(IPCMSG_GETGLOBAL);
159 req.WriteU16(IPC_GLOBATTR_SCREENDIMS);
160 req.WriteU8(ScreenIndex);
162 CDeserialiser response = GetSyncReply(req, IPCMSG_GETGLOBAL);
163 if( response.ReadU16() != IPC_GLOBATTR_SCREENDIMS ) {
167 *Width = response.ReadU16();
168 *Height = response.ReadU16();
170 _SysDebug("AxWin4_GetScreenDimensions: %i = %ix%i", ScreenIndex, *Width, *Height);
173 IIPCChannel::~IIPCChannel()
177 }; // namespace AxWin