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>
22 #include <draw_text.hpp>
27 CCompositor* gpCompositor;
28 ::std::list<IIPCChannel*> glChannels;
29 ::std::map<uint16_t,CClient*> glClients;
30 uint16_t giNextClient = 1;
32 void Initialise(const CConfigIPC& config, CCompositor& compositor)
34 gpCompositor = &compositor;
36 ::std::string pipe_basepath = "axwin4";
37 glChannels.push_back( new CIPCChannel_AcessIPCPipe( pipe_basepath ) );
39 //glChannels.push_back( new CIPCChannel_TCP("0.0.0.0:2100") );
41 //for( auto channel : config.m_channels )
43 // channels.push_back( );
47 int FillSelect(fd_set& rfds)
50 for( const auto channel : glChannels )
53 ret = ::std::max(ret, channel->FillSelect(rfds));
58 void HandleSelect(const fd_set& rfds)
60 for( const auto channel : glChannels )
63 channel->HandleSelect(rfds);
67 void RegisterClient(CClient& client)
69 _SysDebug("RegisterClient(&client=%p)", &client);
70 // allocate a client ID, and save
71 for( int i = 0; i < 100; i ++ )
73 uint16_t id = giNextClient++;
74 if(giNextClient == 0) giNextClient = 1;
75 auto r = glClients.insert( ::std::pair<uint16_t,CClient*>(id, &client) );
76 if( r.second == true )
82 // Wut? 100 attempts and fail!
83 assert(!"Todo - Better way of handling client ID reuse");
86 CClient* GetClientByID(uint16_t id)
88 auto it = glClients.find(id);
89 if(it == glClients.end()) {
90 //_SysDebug("Client %i not registered", id);
94 //_SysDebug("Client %i %i = %p", id, it->first, it->second);
99 void DeregisterClient(CClient& client)
101 glClients.erase( client.id() );
105 void SendMessage_NotifyDims(CClient& client, unsigned int WinID, unsigned int NewW, unsigned int NewH)
107 _SysDebug("TODO: IPC::SendMessage_NotifyDims");
109 void SendMessage_MouseButton(CClient& client, unsigned int WinID, unsigned int X, unsigned int Y, uint8_t Button, bool Pressed)
112 msg.WriteU8(IPCMSG_INPUTEVENT);
113 msg.WriteU8(IPC_INEV_MOUSEBTN);
118 msg.WriteU8(Pressed ? 0 : 1);
119 client.SendMessage(msg);
121 void SendMessage_MouseMove(CClient& client, unsigned int WinID, unsigned int X, unsigned int Y)
123 _SysDebug("TODO: IPC::SendMessage_MouseMove");
125 void SendMessage_KeyEvent(CClient& client, unsigned int WinID, uint32_t KeySym, bool Pressed, const char *Translated)
128 msg.WriteU8(IPCMSG_INPUTEVENT);
129 msg.WriteU8(IPC_INEV_KEYBOARD);
131 msg.WriteU16(KeySym);
132 msg.WriteU8(Pressed ? 0 : 1);
133 msg.WriteString(Translated);
134 client.SendMessage(msg);
138 void HandleMessage_Nop(CClient& client, CDeserialiser& message)
142 void HandleMessage_Reply(CClient& client, CDeserialiser& message)
144 // Reply to a sent message
145 // - Not many messages need server-bound replies
146 int orig_command = message.ReadU8();
150 // Ping reply, mark client as still responding
158 void HandleMessage_Ping(CClient& client, CDeserialiser& message)
160 // A client has asked for a ping, we pong them back
162 reply.WriteU8(IPCMSG_REPLY);
163 reply.WriteU8(IPCMSG_PING);
164 client.SendMessage(reply);
167 void HandleMessage_GetGlobalAttr(CClient& client, CDeserialiser& message)
169 uint16_t attr_id = message.ReadU16();
172 reply.WriteU8(IPCMSG_REPLY);
173 reply.WriteU8(IPCMSG_GETGLOBAL);
174 reply.WriteU16(attr_id);
178 case IPC_GLOBATTR_SCREENDIMS: {
179 uint8_t screen_id = message.ReadU8();
181 gpCompositor->GetScreenDims(screen_id, &w, &h);
182 reply.WriteU16( (w <= UINT16_MAX ? w : UINT16_MAX) );
183 reply.WriteU16( (h <= UINT16_MAX ? h : UINT16_MAX) );
185 case IPC_GLOBATTR_MAXAREA:
186 assert(!"TODO: IPC_GLOBATTR_MAXAREA");
189 throw IPC::CClientFailure("Bad global attribute ID");
192 client.SendMessage(reply);
195 void HandleMessage_SetGlobalAttr(CClient& client, CDeserialiser& message)
197 uint16_t attr_id = message.ReadU16();
201 case IPC_GLOBATTR_SCREENDIMS:
204 case IPC_GLOBATTR_MAXAREA:
205 assert(!"TODO: IPC_GLOBATTR_MAXAREA");
208 throw IPC::CClientFailure("Bad global attribute ID");
212 void HandleMessage_CreateWindow(CClient& client, CDeserialiser& message)
214 uint16_t new_id = message.ReadU16();
215 //uint16_t parent_id = message.ReadU16();
216 //CWindow* parent = client.GetWindow( parent_id );
217 ::std::string name = message.ReadString();
219 ::_SysDebug("_CreateWindow: (%i, '%s')", new_id, name.c_str());
220 client.SetWindow( new_id, new CWindow(*gpCompositor, client, name, new_id) );
223 void HandleMessage_DestroyWindow(CClient& client, CDeserialiser& message)
225 uint16_t win_id = message.ReadU16();
226 _SysDebug("_DestroyWindow: (%i)", win_id);
228 CWindow* win = client.GetWindow(win_id);
230 throw IPC::CClientFailure("_DestroyWindow: Bad window");
232 client.SetWindow(win_id, 0);
234 // TODO: Directly inform compositor?
238 void HandleMessage_SetWindowAttr(CClient& client, CDeserialiser& message)
240 uint16_t win_id = message.ReadU16();
241 uint16_t attr_id = message.ReadU16();
242 _SysDebug("_SetWindowAttr: (Win=%i, ID=%i)", win_id, attr_id);
244 CWindow* win = client.GetWindow(win_id);
246 throw IPC::CClientFailure("_SetWindowAttr - Bad window");
251 case IPC_WINATTR_DIMENSIONS: {
252 uint16_t new_w = message.ReadU16();
253 uint16_t new_h = message.ReadU16();
254 win->Resize(new_w, new_h);
256 case IPC_WINATTR_POSITION: {
257 int16_t new_x = message.ReadS16();
258 int16_t new_y = message.ReadS16();
259 win->Move(new_x, new_y);
261 case IPC_WINATTR_SHOW:
262 win->Show( message.ReadU8() != 0 );
264 case IPC_WINATTR_FLAGS:
265 win->SetFlags( message.ReadU8() ); // TODO: U8? why so small?
267 case IPC_WINATTR_TITLE:
268 assert(!"TODO: IPC_WINATTR_TITLE");
271 _SysDebug("HandleMessage_SetWindowAttr - Bad attr %u", attr_id);
272 throw IPC::CClientFailure("Bad window attr");
276 void HandleMessage_GetWindowAttr(CClient& client, CDeserialiser& message)
278 assert(!"TODO HandleMessage_GetWindowAttr");
281 void HandleMessage_SendIPC(CClient& client, CDeserialiser& message)
283 assert(!"TODO HandleMessage_SendIPC");
286 void HandleMessage_GetWindowBuffer(CClient& client, CDeserialiser& message)
288 uint16_t win_id = message.ReadU16();
289 _SysDebug("_GetWindowBuffer: (%i)", win_id);
291 CWindow* win = client.GetWindow(win_id);
293 throw IPC::CClientFailure("_PushData: Bad window");
296 uint64_t handle = win->m_surface.GetSHMHandle();
299 reply.WriteU8(IPCMSG_REPLY);
300 reply.WriteU8(IPCMSG_GETWINBUF);
301 reply.WriteU16(win_id);
302 reply.WriteU64(handle);
303 client.SendMessage(reply);
306 void HandleMessage_DamageRect(CClient& client, CDeserialiser& message)
308 uint16_t winid = message.ReadU16();
309 uint16_t x = message.ReadU16();
310 uint16_t y = message.ReadU16();
311 uint16_t w = message.ReadU16();
312 uint16_t h = message.ReadU16();
314 _SysDebug("_DamageRect: (%i %i,%i %ix%i)", winid, x, y, w, h);
316 CWindow* win = client.GetWindow(winid);
318 throw IPC::CClientFailure("_PushData: Bad window");
326 void HandleMessage_PushData(CClient& client, CDeserialiser& message)
328 uint16_t win_id = message.ReadU16();
329 uint16_t x = message.ReadU16();
330 uint16_t y = message.ReadU16();
331 uint16_t w = message.ReadU16();
332 uint16_t h = message.ReadU16();
333 _SysDebug("_PushData: (%i, (%i,%i) %ix%i)", win_id, x, y, w, h);
335 CWindow* win = client.GetWindow(win_id);
337 throw IPC::CClientFailure("_PushData: Bad window");
340 for( unsigned int row = 0; row < h; row ++ )
342 const ::std::vector<uint8_t> scanline_data = message.ReadBuffer();
343 if( scanline_data.size() != w * 4 ) {
344 _SysDebug("ERROR _PushData: Scanline buffer size mismatch (%i,%i)",
345 scanline_data.size(), w*4);
348 win->DrawScanline(y+row, x, w, scanline_data.data());
351 void HandleMessage_Blit(CClient& client, CDeserialiser& message)
353 assert(!"TODO HandleMessage_Blit");
355 void HandleMessage_DrawCtl(CClient& client, CDeserialiser& message)
357 uint16_t win_id = message.ReadU16();
358 uint16_t x = message.ReadU16();
359 uint16_t y = message.ReadU16();
360 uint16_t w = message.ReadU16();
361 uint16_t h = message.ReadU16();
362 uint16_t ctrl_id = message.ReadU16();
363 uint16_t frame = message.ReadU16();
364 _SysDebug("_DrawCtl: (%i, (%i,%i) %ix%i Ctl%i frame?=0x%04x)", win_id, x, y, w, h, ctrl_id, frame);
366 CWindow* win = client.GetWindow(win_id);
368 throw IPC::CClientFailure("_DrawCtl: Bad window");
371 const CControl* ctrl = CControl::GetByID(ctrl_id);
373 throw IPC::CClientFailure("_DrawCtl: Invalid control ID");
377 ctrl->Render(win->m_surface, area);
379 void HandleMessage_DrawText(CClient& client, CDeserialiser& message)
381 uint16_t win_id = message.ReadU16();
382 uint16_t x = message.ReadU16();
383 uint16_t y = message.ReadU16();
384 uint16_t w = message.ReadU16();
385 uint16_t h = message.ReadU16();
386 uint16_t font_id = message.ReadU16();
387 ::std::string str = message.ReadString();
388 _SysDebug("_DrawText: (%i (%i,%i) %ix%i Font%i \"%s\")", win_id, x, y, w, h, font_id, str.c_str());
390 CWindow* win = client.GetWindow(win_id);
392 throw IPC::CClientFailure("_DrawText: Bad window");
395 // 1. Get font from client structure
396 IFontFace& fontface = client.GetFont(font_id);
399 CRect area(x, y, w, h);
400 fontface.Render(win->m_surface, area, str, h);
403 void HandleMessage_FillRect(CClient& client, CDeserialiser& message)
405 uint16_t win_id = message.ReadU16();
406 uint16_t x = message.ReadU16();
407 uint16_t y = message.ReadU16();
408 uint16_t w = message.ReadU16();
409 uint16_t h = message.ReadU16();
410 uint32_t colour = message.ReadU32();
411 _SysDebug("_FillRect: (%i (%i,%i) %ix%i %06x)", win_id, x, y, w, h, colour);
413 CWindow* win = client.GetWindow(win_id);
415 throw IPC::CClientFailure("_FillRect: Bad window");
419 win->FillScanline(y++, x, w, colour);
423 void HandleMessage_DrawRect(CClient& client, CDeserialiser& message)
425 uint16_t win_id = message.ReadU16();
426 uint16_t x = message.ReadU16();
427 uint16_t y = message.ReadU16();
428 uint16_t w = message.ReadU16();
429 uint16_t h = message.ReadU16();
430 uint32_t colour = message.ReadU32();
431 _SysDebug("_DrawRect: (%i (%i,%i) %ix%i %06x)", win_id, x, y, w, h, colour);
433 CWindow* win = client.GetWindow(win_id);
435 throw IPC::CClientFailure("_DrawRect: Bad window");
441 win->FillScanline(y, x, w, colour);
444 win->FillScanline(y++, x, w, colour);
445 win->FillScanline(y++, x, w, colour);
448 win->FillScanline(y++, x, w, colour);
450 win->FillScanline(y, x, 1, colour);
451 win->FillScanline(y, x+w-1, 1, colour);
454 win->FillScanline(y++, x, w, colour);
458 typedef void MessageHandler_op_t(CClient& client, CDeserialiser& message);
460 MessageHandler_op_t *message_handlers[] = {
461 [IPCMSG_NULL] = &HandleMessage_Nop,
462 [IPCMSG_REPLY] = &HandleMessage_Reply,
463 [IPCMSG_PING] = &HandleMessage_Ping,
464 [IPCMSG_GETGLOBAL] = &HandleMessage_GetGlobalAttr,
465 [IPCMSG_SETGLOBAL] = &HandleMessage_SetGlobalAttr,
467 [IPCMSG_CREATEWIN] = &HandleMessage_CreateWindow,
468 [IPCMSG_CLOSEWIN] = &HandleMessage_DestroyWindow,
469 [IPCMSG_SETWINATTR] = &HandleMessage_SetWindowAttr,
470 [IPCMSG_GETWINATTR] = &HandleMessage_GetWindowAttr,
471 [IPCMSG_SENDIPC] = &HandleMessage_SendIPC, // Use the GUI server for low-bandwith IPC
472 [IPCMSG_GETWINBUF] = &HandleMessage_GetWindowBuffer,
473 [IPCMSG_DAMAGERECT] = &HandleMessage_DamageRect,
474 [IPCMSG_PUSHDATA] = &HandleMessage_PushData, // to a window's buffer
475 [IPCMSG_BLIT] = &HandleMessage_Blit, // Copy data from one part of the window to another
476 [IPCMSG_DRAWCTL] = &HandleMessage_DrawCtl, // Draw a control
477 [IPCMSG_DRAWTEXT] = &HandleMessage_DrawText, // Draw text
478 [IPCMSG_FILLRECT] = &HandleMessage_FillRect, // Fill a rectangle
479 [IPCMSG_DRAWRECT] = &HandleMessage_DrawRect, // Draw (outline) a rectangle
482 void HandleMessage(CClient& client, CDeserialiser& message)
484 const unsigned int num_commands = sizeof(message_handlers)/sizeof(IPC::MessageHandler_op_t*);
485 unsigned int command = message.ReadU8();
486 if( command >= num_commands ) {
487 // Drop, invalid command
488 _SysDebug("HandleMessage: Command %u is invalid (out of range for %u)", command, num_commands);
492 (message_handlers[command])(client, message);
495 CClientFailure::CClientFailure(std::string&& what):
499 const char *CClientFailure::what() const throw()
501 return m_what.c_str();
503 CClientFailure::~CClientFailure() throw()
509 IIPCChannel::~IIPCChannel()
513 }; // namespace AxWin