3 * - By John Hodge (thePowersGang)
6 * - Client-Server communication (dispatch)
8 #define __STDC_LIMIT_MACROS
11 #include <IIPCChannel.hpp>
13 #include <CClient.hpp>
14 #include <serialisation.hpp>
15 #include <ipc_proto.hpp>
16 #include <CCompositor.hpp>
20 #include <CIPCChannel_AcessIPCPipe.hpp>
21 #include <draw_control.hpp>
26 CCompositor* gpCompositor;
27 ::std::list<IIPCChannel*> glChannels;
28 ::std::map<uint16_t,CClient*> glClients;
29 uint16_t giNextClient = 1;
31 void Initialise(const CConfigIPC& config, CCompositor& compositor)
33 gpCompositor = &compositor;
35 ::std::string pipe_basepath = "axwin4";
36 glChannels.push_back( new CIPCChannel_AcessIPCPipe( pipe_basepath ) );
38 //glChannels.push_back( new CIPCChannel_TCP("0.0.0.0:2100") );
40 //for( auto channel : config.m_channels )
42 // channels.push_back( );
46 int FillSelect(fd_set& rfds)
49 for( const auto channel : glChannels )
52 ret = ::std::max(ret, channel->FillSelect(rfds));
57 void HandleSelect(const fd_set& rfds)
59 for( const auto channel : glChannels )
62 channel->HandleSelect(rfds);
66 void RegisterClient(CClient& client)
68 _SysDebug("RegisterClient(&client=%p)", &client);
69 // allocate a client ID, and save
70 for( int i = 0; i < 100; i ++ )
72 uint16_t id = giNextClient++;
73 if(giNextClient == 0) giNextClient = 1;
74 auto r = glClients.insert( ::std::pair<uint16_t,CClient*>(id, &client) );
75 if( r.second == true )
81 // Wut? 100 attempts and fail!
82 assert(!"Todo - Better way of handling client ID reuse");
85 CClient* GetClientByID(uint16_t id)
87 auto it = glClients.find(id);
88 if(it == glClients.end()) {
89 //_SysDebug("Client %i not registered", id);
93 //_SysDebug("Client %i %i = %p", id, it->first, it->second);
98 void DeregisterClient(CClient& client)
100 glClients.erase( client.id() );
104 void SendMessage_NotifyDims(CClient& client, unsigned int NewW, unsigned int NewH)
106 _SysDebug("TODO: CClient::SendNotify_Dims");
110 void HandleMessage_Nop(CClient& client, CDeserialiser& message)
114 void HandleMessage_Reply(CClient& client, CDeserialiser& message)
116 // Reply to a sent message
117 // - Not many messages need server-bound replies
118 int orig_command = message.ReadU8();
122 // Ping reply, mark client as still responding
130 void HandleMessage_Ping(CClient& client, CDeserialiser& message)
132 // A client has asked for a ping, we pong them back
134 reply.WriteU8(IPCMSG_REPLY);
135 reply.WriteU8(IPCMSG_PING);
136 client.SendMessage(reply);
139 void HandleMessage_GetGlobalAttr(CClient& client, CDeserialiser& message)
141 uint16_t attr_id = message.ReadU16();
144 reply.WriteU8(IPCMSG_REPLY);
145 reply.WriteU8(IPCMSG_GETGLOBAL);
146 reply.WriteU16(attr_id);
150 case IPC_GLOBATTR_SCREENDIMS: {
151 uint8_t screen_id = message.ReadU8();
153 gpCompositor->GetScreenDims(screen_id, &w, &h);
154 reply.WriteU16( (w <= UINT16_MAX ? w : UINT16_MAX) );
155 reply.WriteU16( (h <= UINT16_MAX ? h : UINT16_MAX) );
157 case IPC_GLOBATTR_MAXAREA:
158 assert(!"TODO: IPC_GLOBATTR_MAXAREA");
161 throw IPC::CClientFailure("Bad global attribute ID");
164 client.SendMessage(reply);
167 void HandleMessage_SetGlobalAttr(CClient& client, CDeserialiser& message)
169 uint16_t attr_id = message.ReadU16();
173 case IPC_GLOBATTR_SCREENDIMS:
176 case IPC_GLOBATTR_MAXAREA:
177 assert(!"TODO: IPC_GLOBATTR_MAXAREA");
180 throw IPC::CClientFailure("Bad global attribute ID");
184 void HandleMessage_CreateWindow(CClient& client, CDeserialiser& message)
186 uint16_t new_id = message.ReadU16();
187 //uint16_t parent_id = message.ReadU16();
188 //CWindow* parent = client.GetWindow( parent_id );
189 ::std::string name = message.ReadString();
191 ::_SysDebug("_CreateWindow: (%i, '%s')", new_id, name.c_str());
192 client.SetWindow( new_id, new CWindow(*gpCompositor, client, name, new_id) );
195 void HandleMessage_DestroyWindow(CClient& client, CDeserialiser& message)
197 uint16_t win_id = message.ReadU16();
198 _SysDebug("_DestroyWindow: (%i)", win_id);
200 CWindow* win = client.GetWindow(win_id);
202 throw IPC::CClientFailure("_DestroyWindow: Bad window");
204 client.SetWindow(win_id, 0);
206 // TODO: Directly inform compositor?
210 void HandleMessage_SetWindowAttr(CClient& client, CDeserialiser& message)
212 uint16_t win_id = message.ReadU16();
213 uint16_t attr_id = message.ReadU16();
214 _SysDebug("_SetWindowAttr: (Win=%i, ID=%i)", win_id, attr_id);
216 CWindow* win = client.GetWindow(win_id);
218 throw IPC::CClientFailure("_SetWindowAttr - Bad window");
223 case IPC_WINATTR_DIMENSIONS: {
224 uint16_t new_w = message.ReadU16();
225 uint16_t new_h = message.ReadU16();
226 win->Resize(new_w, new_h);
228 case IPC_WINATTR_POSITION: {
229 int16_t new_x = message.ReadS16();
230 int16_t new_y = message.ReadS16();
231 win->Move(new_x, new_y);
233 case IPC_WINATTR_SHOW:
234 win->Show( message.ReadU8() != 0 );
236 case IPC_WINATTR_FLAGS:
237 win->SetFlags( message.ReadU8() ); // TODO: U8? why so small?
239 case IPC_WINATTR_TITLE:
240 assert(!"TODO: IPC_WINATTR_TITLE");
243 _SysDebug("HandleMessage_SetWindowAttr - Bad attr %u", attr_id);
244 throw IPC::CClientFailure("Bad window attr");
248 void HandleMessage_GetWindowAttr(CClient& client, CDeserialiser& message)
250 assert(!"TODO HandleMessage_GetWindowAttr");
253 void HandleMessage_SendIPC(CClient& client, CDeserialiser& message)
255 assert(!"TODO HandleMessage_SendIPC");
258 void HandleMessage_GetWindowBuffer(CClient& client, CDeserialiser& message)
260 uint16_t win_id = message.ReadU16();
261 _SysDebug("_GetWindowBuffer: (%i)", win_id);
263 CWindow* win = client.GetWindow(win_id);
265 throw IPC::CClientFailure("_PushData: Bad window");
268 uint64_t handle = win->m_surface.GetSHMHandle();
271 reply.WriteU8(IPCMSG_REPLY);
272 reply.WriteU8(IPCMSG_GETWINBUF);
273 reply.WriteU16(win_id);
274 reply.WriteU64(handle);
275 client.SendMessage(reply);
278 void HandleMessage_DamageRect(CClient& client, CDeserialiser& message)
280 uint16_t winid = message.ReadU16();
281 uint16_t x = message.ReadU16();
282 uint16_t y = message.ReadU16();
283 uint16_t w = message.ReadU16();
284 uint16_t h = message.ReadU16();
286 _SysDebug("_DamageRect: (%i %i,%i %ix%i)", winid, x, y, w, h);
288 CWindow* win = client.GetWindow(winid);
290 throw IPC::CClientFailure("_PushData: Bad window");
298 void HandleMessage_PushData(CClient& client, CDeserialiser& message)
300 uint16_t win_id = message.ReadU16();
301 uint16_t x = message.ReadU16();
302 uint16_t y = message.ReadU16();
303 uint16_t w = message.ReadU16();
304 uint16_t h = message.ReadU16();
305 _SysDebug("_PushData: (%i, (%i,%i) %ix%i)", win_id, x, y, w, h);
307 CWindow* win = client.GetWindow(win_id);
309 throw IPC::CClientFailure("_PushData: Bad window");
312 for( unsigned int row = 0; row < h; row ++ )
314 const ::std::vector<uint8_t> scanline_data = message.ReadBuffer();
315 if( scanline_data.size() != w * 4 ) {
316 _SysDebug("ERROR _PushData: Scanline buffer size mismatch (%i,%i)",
317 scanline_data.size(), w*4);
320 win->DrawScanline(y+row, x, w, scanline_data.data());
323 void HandleMessage_Blit(CClient& client, CDeserialiser& message)
325 assert(!"TODO HandleMessage_Blit");
327 void HandleMessage_DrawCtl(CClient& client, CDeserialiser& message)
329 uint16_t win_id = message.ReadU16();
330 uint16_t x = message.ReadU16();
331 uint16_t y = message.ReadU16();
332 uint16_t w = message.ReadU16();
333 uint16_t h = message.ReadU16();
334 uint16_t ctrl_id = message.ReadU16();
335 uint16_t frame = message.ReadU16();
336 _SysDebug("_DrawCtl: (%i, (%i,%i) %ix%i Ctl%i frame?=0x%04x)", win_id, x, y, w, h, ctrl_id, frame);
338 CWindow* win = client.GetWindow(win_id);
340 throw IPC::CClientFailure("_DrawCtl: Bad window");
343 const CControl* ctrl = CControl::GetByID(ctrl_id);
345 throw IPC::CClientFailure("_DrawCtl: Invalid control ID");
349 ctrl->Render(win->m_surface, area);
351 void HandleMessage_DrawText(CClient& client, CDeserialiser& message)
353 uint16_t win_id = message.ReadU16();
354 uint16_t x = message.ReadU16();
355 uint16_t y = message.ReadU16();
356 uint16_t w = message.ReadU16();
357 uint16_t h = message.ReadU16();
358 uint16_t font = message.ReadU16();
359 ::std::string str = message.ReadString();
360 _SysDebug("_DrawText: (%i (%i,%i) %ix%i Font%i \"%s\")", win_id, x, y, w, h, font, str.c_str());
362 CWindow* win = client.GetWindow(win_id);
364 throw IPC::CClientFailure("_DrawText: Bad window");
367 // 1. Get font from client structure
368 //CFont& font = client.GetFont(font_id);
371 //CRect area(x, y, w, h);
372 //font->Render(win->m_surface, area, str, h);
374 _SysDebug("TODO: HandleMessage_DrawText");
377 typedef void MessageHandler_op_t(CClient& client, CDeserialiser& message);
379 MessageHandler_op_t *message_handlers[] = {
380 [IPCMSG_NULL] = &HandleMessage_Nop,
381 [IPCMSG_REPLY] = &HandleMessage_Reply,
382 [IPCMSG_PING] = &HandleMessage_Ping,
383 [IPCMSG_GETGLOBAL] = &HandleMessage_GetGlobalAttr,
384 [IPCMSG_SETGLOBAL] = &HandleMessage_SetGlobalAttr,
386 [IPCMSG_CREATEWIN] = &HandleMessage_CreateWindow,
387 [IPCMSG_CLOSEWIN] = &HandleMessage_DestroyWindow,
388 [IPCMSG_SETWINATTR] = &HandleMessage_SetWindowAttr,
389 [IPCMSG_GETWINATTR] = &HandleMessage_GetWindowAttr,
390 [IPCMSG_SENDIPC] = &HandleMessage_SendIPC, // Use the GUI server for low-bandwith IPC
391 [IPCMSG_GETWINBUF] = &HandleMessage_GetWindowBuffer,
392 [IPCMSG_DAMAGERECT] = &HandleMessage_DamageRect,
393 [IPCMSG_PUSHDATA] = &HandleMessage_PushData, // to a window's buffer
394 [IPCMSG_BLIT] = &HandleMessage_Blit, // Copy data from one part of the window to another
395 [IPCMSG_DRAWCTL] = &HandleMessage_DrawCtl, // Draw a control
396 [IPCMSG_DRAWTEXT] = &HandleMessage_DrawText, // Draw text
399 void HandleMessage(CClient& client, CDeserialiser& message)
401 unsigned int command = message.ReadU8();
402 if( command >= sizeof(message_handlers)/sizeof(IPC::MessageHandler_op_t*) ) {
403 // Drop, invalid command
407 (message_handlers[command])(client, message);
410 CClientFailure::CClientFailure(std::string&& what):
414 const char *CClientFailure::what() const throw()
416 return m_what.c_str();
418 CClientFailure::~CClientFailure() throw()
424 IIPCChannel::~IIPCChannel()
428 }; // namespace AxWin