/*
+ * Acess2 GUI v4
+ * - By John Hodge (thePowersGang)
+ *
+ * ipc.cpp
+ * - Client-Server communication (dispatch)
*/
+#define __STDC_LIMIT_MACROS
#include <ipc.hpp>
#include <list>
#include <IIPCChannel.hpp>
extern "C" {
#include <assert.h>
};
+#include <CIPCChannel_AcessIPCPipe.hpp>
+#include <draw_control.hpp>
+#include <draw_text.hpp>
namespace AxWin {
namespace IPC {
CCompositor* gpCompositor;
-::std::list<IIPCChannel*> channels;
+::std::list<IIPCChannel*> glChannels;
+::std::map<uint16_t,CClient*> glClients;
+uint16_t giNextClient = 1;
-void Initialise(const CConfigIPC& config, CCompositor* compositor)
+void Initialise(const CConfigIPC& config, CCompositor& compositor)
{
- gpCompositor = compositor;
+ gpCompositor = &compositor;
+
+ ::std::string pipe_basepath = "axwin4";
+ glChannels.push_back( new CIPCChannel_AcessIPCPipe( pipe_basepath ) );
+
+ //glChannels.push_back( new CIPCChannel_TCP("0.0.0.0:2100") );
+
//for( auto channel : config.m_channels )
//{
// channels.push_back( );
int FillSelect(fd_set& rfds)
{
int ret = 0;
- for( auto channel : channels )
+ for( const auto channel : glChannels )
{
+ assert(channel);
ret = ::std::max(ret, channel->FillSelect(rfds));
}
return ret;
}
-void HandleSelect(fd_set& rfds)
+void HandleSelect(const fd_set& rfds)
{
-
+ for( const auto channel : glChannels )
+ {
+ assert(channel);
+ channel->HandleSelect(rfds);
+ }
}
-void RegisterClient(IIPCChannel& channel, CClient& client)
+void RegisterClient(CClient& client)
{
-
+ _SysDebug("RegisterClient(&client=%p)", &client);
+ // allocate a client ID, and save
+ for( int i = 0; i < 100; i ++ )
+ {
+ uint16_t id = giNextClient++;
+ if(giNextClient == 0) giNextClient = 1;
+ auto r = glClients.insert( ::std::pair<uint16_t,CClient*>(id, &client) );
+ if( r.second == true )
+ {
+ client.set_id(id);
+ return;
+ }
+ }
+ // Wut? 100 attempts and fail!
+ assert(!"Todo - Better way of handling client ID reuse");
}
+CClient* GetClientByID(uint16_t id)
+{
+ auto it = glClients.find(id);
+ if(it == glClients.end()) {
+ //_SysDebug("Client %i not registered", id);
+ return nullptr;
+ }
+ else {
+ //_SysDebug("Client %i %i = %p", id, it->first, it->second);
+ return it->second;
+ }
+}
+void DeregisterClient(CClient& client)
+{
+ glClients.erase( client.id() );
+}
-typedef void MessageHandler_op_t(CClient& client, CDeserialiser& message);
-MessageHandler_op_t HandleMessage_Ping;
-MessageHandler_op_t HandleMessage_GetWindowAttr;
-MessageHandler_op_t HandleMessage_Reply;
-MessageHandler_op_t HandleMessage_CreateWindow;
-MessageHandler_op_t HandleMessage_CloseWindow;
-MessageHandler_op_t HandleMessage_SetWindowAttr;
-MessageHandler_op_t HandleMessage_AddRegion;
-MessageHandler_op_t HandleMessage_DelRegion;
-MessageHandler_op_t HandleMessage_SetRegionAttr;
-MessageHandler_op_t HandleMessage_PushData;
-MessageHandler_op_t HandleMessage_SendIPC;
-MessageHandler_op_t *message_handlers[] = {
- [IPCMSG_PING] = &HandleMessage_Ping,
- [IPCMSG_REPLY] = &HandleMessage_Reply,
-
- [IPCMSG_CREATEWIN] = &HandleMessage_CreateWindow,
- [IPCMSG_CLOSEWIN] = &HandleMessage_CloseWindow,
- [IPCMSG_SETWINATTR] = &HandleMessage_SetWindowAttr,
- [IPCMSG_GETWINATTR] = &HandleMessage_GetWindowAttr,
-
- [IPCMSG_RGNADD] = &HandleMessage_AddRegion,
- [IPCMSG_RGNDEL] = &HandleMessage_DelRegion,
- [IPCMSG_RGNSETATTR] = &HandleMessage_SetRegionAttr,
- [IPCMSG_RGNPUSHDATA]= &HandleMessage_PushData, // to a region
- [IPCMSG_SENDIPC] = &HandleMessage_SendIPC, // Use the GUI server for low-bandwith inter-process messaging
-};
-
-void HandleMessage(CClient& client, CDeserialiser& message)
+void SendMessage_NotifyDims(CClient& client, unsigned int WinID, unsigned int NewW, unsigned int NewH)
{
- unsigned int command = message.ReadU8();
- if( command >= sizeof(message_handlers)/sizeof(IPC::MessageHandler_op_t*) ) {
- // Drop, invalid command
- return ;
- }
-
- (message_handlers[command])(client, message);
+ _SysDebug("TODO: IPC::SendMessage_NotifyDims");
+}
+void SendMessage_MouseButton(CClient& client, unsigned int WinID, unsigned int X, unsigned int Y, uint8_t Button, bool Pressed)
+{
+ CSerialiser msg;
+ msg.WriteU8(IPCMSG_INPUTEVENT);
+ msg.WriteU8(IPC_INEV_MOUSEBTN);
+ msg.WriteU16(WinID);
+ msg.WriteU16(X);
+ msg.WriteU16(Y);
+ msg.WriteU8(Button);
+ msg.WriteU8(Pressed ? 0 : 1);
+ client.SendMessage(msg);
+}
+void SendMessage_MouseMove(CClient& client, unsigned int WinID, unsigned int X, unsigned int Y)
+{
+ _SysDebug("TODO: IPC::SendMessage_MouseMove");
+}
+void SendMessage_KeyEvent(CClient& client, unsigned int WinID, uint32_t KeySym, bool Pressed, const char *Translated)
+{
+ CSerialiser msg;
+ msg.WriteU8(IPCMSG_INPUTEVENT);
+ msg.WriteU8(IPC_INEV_KEYBOARD);
+ msg.WriteU16(WinID);
+ msg.WriteU16(KeySym);
+ msg.WriteU8(Pressed ? 0 : 1);
+ msg.WriteString(Translated);
+ client.SendMessage(msg);
}
+
+void HandleMessage_Nop(CClient& client, CDeserialiser& message)
+{
+ // Do nothing
+}
void HandleMessage_Reply(CClient& client, CDeserialiser& message)
{
// Reply to a sent message
client.SendMessage(reply);
}
+void HandleMessage_GetGlobalAttr(CClient& client, CDeserialiser& message)
+{
+ uint16_t attr_id = message.ReadU16();
+
+ CSerialiser reply;
+ reply.WriteU8(IPCMSG_REPLY);
+ reply.WriteU8(IPCMSG_GETGLOBAL);
+ reply.WriteU16(attr_id);
+
+ switch(attr_id)
+ {
+ case IPC_GLOBATTR_SCREENDIMS: {
+ uint8_t screen_id = message.ReadU8();
+ unsigned int w, h;
+ gpCompositor->GetScreenDims(screen_id, &w, &h);
+ reply.WriteU16( (w <= UINT16_MAX ? w : UINT16_MAX) );
+ reply.WriteU16( (h <= UINT16_MAX ? h : UINT16_MAX) );
+ break; }
+ case IPC_GLOBATTR_MAXAREA:
+ assert(!"TODO: IPC_GLOBATTR_MAXAREA");
+ break;
+ default:
+ throw IPC::CClientFailure("Bad global attribute ID");
+ }
+
+ client.SendMessage(reply);
+}
+
+void HandleMessage_SetGlobalAttr(CClient& client, CDeserialiser& message)
+{
+ uint16_t attr_id = message.ReadU16();
+
+ switch(attr_id)
+ {
+ case IPC_GLOBATTR_SCREENDIMS:
+ // Setting readonly
+ break;
+ case IPC_GLOBATTR_MAXAREA:
+ assert(!"TODO: IPC_GLOBATTR_MAXAREA");
+ break;
+ default:
+ throw IPC::CClientFailure("Bad global attribute ID");
+ }
+}
+
void HandleMessage_CreateWindow(CClient& client, CDeserialiser& message)
{
- uint16_t parent_id = message.ReadU16();
uint16_t new_id = message.ReadU16();
- CWindow* parent = client.GetWindow( parent_id );
+ //uint16_t parent_id = message.ReadU16();
+ //CWindow* parent = client.GetWindow( parent_id );
+ ::std::string name = message.ReadString();
- client.SetWindow( new_id, gpCompositor->CreateWindow(client) );
+ ::_SysDebug("_CreateWindow: (%i, '%s')", new_id, name.c_str());
+ client.SetWindow( new_id, new CWindow(*gpCompositor, client, name, new_id) );
}
-void HandleMessage_CloseWindow(CClient& client, CDeserialiser& message)
+void HandleMessage_DestroyWindow(CClient& client, CDeserialiser& message)
{
- assert(!"TODO");
+ uint16_t win_id = message.ReadU16();
+ _SysDebug("_DestroyWindow: (%i)", win_id);
+
+ CWindow* win = client.GetWindow(win_id);
+ if(!win) {
+ throw IPC::CClientFailure("_DestroyWindow: Bad window");
+ }
+ client.SetWindow(win_id, 0);
+
+ // TODO: Directly inform compositor?
+ delete win;
}
void HandleMessage_SetWindowAttr(CClient& client, CDeserialiser& message)
{
- assert(!"TODO");
+ uint16_t win_id = message.ReadU16();
+ uint16_t attr_id = message.ReadU16();
+ _SysDebug("_SetWindowAttr: (Win=%i, ID=%i)", win_id, attr_id);
+
+ CWindow* win = client.GetWindow(win_id);
+ if(!win) {
+ throw IPC::CClientFailure("_SetWindowAttr - Bad window");
+ }
+
+ switch(attr_id)
+ {
+ case IPC_WINATTR_DIMENSIONS: {
+ uint16_t new_w = message.ReadU16();
+ uint16_t new_h = message.ReadU16();
+ win->Resize(new_w, new_h);
+ break; }
+ case IPC_WINATTR_POSITION: {
+ int16_t new_x = message.ReadS16();
+ int16_t new_y = message.ReadS16();
+ win->Move(new_x, new_y);
+ break; }
+ case IPC_WINATTR_SHOW:
+ win->Show( message.ReadU8() != 0 );
+ break;
+ case IPC_WINATTR_FLAGS:
+ win->SetFlags( message.ReadU8() ); // TODO: U8? why so small?
+ break;
+ case IPC_WINATTR_TITLE:
+ assert(!"TODO: IPC_WINATTR_TITLE");
+ break;
+ default:
+ _SysDebug("HandleMessage_SetWindowAttr - Bad attr %u", attr_id);
+ throw IPC::CClientFailure("Bad window attr");
+ }
}
void HandleMessage_GetWindowAttr(CClient& client, CDeserialiser& message)
{
- assert(!"TODO");
+ assert(!"TODO HandleMessage_GetWindowAttr");
}
-void HandleMessage_AddRegion(CClient& client, CDeserialiser& message)
+void HandleMessage_SendIPC(CClient& client, CDeserialiser& message)
{
- assert(!"TODO");
+ assert(!"TODO HandleMessage_SendIPC");
}
-void HandleMessage_DelRegion(CClient& client, CDeserialiser& message)
+void HandleMessage_GetWindowBuffer(CClient& client, CDeserialiser& message)
{
- assert(!"TODO");
+ uint16_t win_id = message.ReadU16();
+ _SysDebug("_GetWindowBuffer: (%i)", win_id);
+
+ CWindow* win = client.GetWindow(win_id);
+ if(!win) {
+ throw IPC::CClientFailure("_PushData: Bad window");
+ }
+
+ uint64_t handle = win->m_surface.GetSHMHandle();
+
+ CSerialiser reply;
+ reply.WriteU8(IPCMSG_REPLY);
+ reply.WriteU8(IPCMSG_GETWINBUF);
+ reply.WriteU16(win_id);
+ reply.WriteU64(handle);
+ client.SendMessage(reply);
}
-void HandleMessage_SetRegionAttr(CClient& client, CDeserialiser& message)
+void HandleMessage_DamageRect(CClient& client, CDeserialiser& message)
{
- assert(!"TODO");
+ uint16_t winid = message.ReadU16();
+ uint16_t x = message.ReadU16();
+ uint16_t y = message.ReadU16();
+ uint16_t w = message.ReadU16();
+ uint16_t h = message.ReadU16();
+
+ _SysDebug("_DamageRect: (%i %i,%i %ix%i)", winid, x, y, w, h);
+
+ CWindow* win = client.GetWindow(winid);
+ if(!win) {
+ throw IPC::CClientFailure("_PushData: Bad window");
+ }
+
+ CRect area(x,y,w,h);
+
+ win->Repaint(area);
}
void HandleMessage_PushData(CClient& client, CDeserialiser& message)
{
- assert(!"TODO");
+ uint16_t win_id = message.ReadU16();
+ uint16_t x = message.ReadU16();
+ uint16_t y = message.ReadU16();
+ uint16_t w = message.ReadU16();
+ uint16_t h = message.ReadU16();
+ _SysDebug("_PushData: (%i, (%i,%i) %ix%i)", win_id, x, y, w, h);
+
+ CWindow* win = client.GetWindow(win_id);
+ if(!win) {
+ throw IPC::CClientFailure("_PushData: Bad window");
+ }
+
+ for( unsigned int row = 0; row < h; row ++ )
+ {
+ const ::std::vector<uint8_t> scanline_data = message.ReadBuffer();
+ if( scanline_data.size() != w * 4 ) {
+ _SysDebug("ERROR _PushData: Scanline buffer size mismatch (%i,%i)",
+ scanline_data.size(), w*4);
+ continue ;
+ }
+ win->DrawScanline(y+row, x, w, scanline_data.data());
+ }
+}
+void HandleMessage_Blit(CClient& client, CDeserialiser& message)
+{
+ assert(!"TODO HandleMessage_Blit");
+}
+void HandleMessage_DrawCtl(CClient& client, CDeserialiser& message)
+{
+ uint16_t win_id = message.ReadU16();
+ uint16_t x = message.ReadU16();
+ uint16_t y = message.ReadU16();
+ uint16_t w = message.ReadU16();
+ uint16_t h = message.ReadU16();
+ uint16_t ctrl_id = message.ReadU16();
+ uint16_t frame = message.ReadU16();
+ _SysDebug("_DrawCtl: (%i, (%i,%i) %ix%i Ctl%i frame?=0x%04x)", win_id, x, y, w, h, ctrl_id, frame);
+
+ CWindow* win = client.GetWindow(win_id);
+ if(!win) {
+ throw IPC::CClientFailure("_DrawCtl: Bad window");
+ }
+
+ const CControl* ctrl = CControl::GetByID(ctrl_id);
+ if(!ctrl) {
+ throw IPC::CClientFailure("_DrawCtl: Invalid control ID");
+ }
+
+ CRect area(x,y,w,h);
+ ctrl->Render(win->m_surface, area);
+}
+void HandleMessage_DrawText(CClient& client, CDeserialiser& message)
+{
+ uint16_t win_id = message.ReadU16();
+ uint16_t x = message.ReadU16();
+ uint16_t y = message.ReadU16();
+ uint16_t w = message.ReadU16();
+ uint16_t h = message.ReadU16();
+ uint16_t font_id = message.ReadU16();
+ ::std::string str = message.ReadString();
+ _SysDebug("_DrawText: (%i (%i,%i) %ix%i Font%i \"%s\")", win_id, x, y, w, h, font_id, str.c_str());
+
+ CWindow* win = client.GetWindow(win_id);
+ if(!win) {
+ throw IPC::CClientFailure("_DrawText: Bad window");
+ }
+
+ // 1. Get font from client structure
+ IFontFace& fontface = client.GetFont(font_id);
+
+ // 2. Render
+ CRect area(x, y, w, h);
+ fontface.Render(win->m_surface, area, str, h);
}
-void HandleMessage_SendIPC(CClient& client, CDeserialiser& message)
+void HandleMessage_FillRect(CClient& client, CDeserialiser& message)
{
- assert(!"TODO");
+ uint16_t win_id = message.ReadU16();
+ uint16_t x = message.ReadU16();
+ uint16_t y = message.ReadU16();
+ uint16_t w = message.ReadU16();
+ uint16_t h = message.ReadU16();
+ uint32_t colour = message.ReadU32();
+ _SysDebug("_FillRect: (%i (%i,%i) %ix%i %06x)", win_id, x, y, w, h, colour);
+
+ CWindow* win = client.GetWindow(win_id);
+ if(!win) {
+ throw IPC::CClientFailure("_FillRect: Bad window");
+ }
+
+ while(h -- ) {
+ win->FillScanline(y++, x, w, colour);
+ }
}
+void HandleMessage_DrawRect(CClient& client, CDeserialiser& message)
+{
+ uint16_t win_id = message.ReadU16();
+ uint16_t x = message.ReadU16();
+ uint16_t y = message.ReadU16();
+ uint16_t w = message.ReadU16();
+ uint16_t h = message.ReadU16();
+ uint32_t colour = message.ReadU32();
+ _SysDebug("_DrawRect: (%i (%i,%i) %ix%i %06x)", win_id, x, y, w, h, colour);
+
+ CWindow* win = client.GetWindow(win_id);
+ if(!win) {
+ throw IPC::CClientFailure("_DrawRect: Bad window");
+ }
+
+ if(h == 0) {
+ }
+ else if(h == 1) {
+ win->FillScanline(y, x, w, colour);
+ }
+ else if(h == 2) {
+ win->FillScanline(y++, x, w, colour);
+ win->FillScanline(y++, x, w, colour);
+ }
+ else {
+ win->FillScanline(y++, x, w, colour);
+ while( h -- > 2 ) {
+ win->FillScanline(y, x, 1, colour);
+ win->FillScanline(y, x+w-1, 1, colour);
+ y ++;
+ }
+ win->FillScanline(y++, x, w, colour);
+ }
+}
+
+typedef void MessageHandler_op_t(CClient& client, CDeserialiser& message);
+
+MessageHandler_op_t *message_handlers[] = {
+ [IPCMSG_NULL] = &HandleMessage_Nop,
+ [IPCMSG_REPLY] = &HandleMessage_Reply,
+ [IPCMSG_PING] = &HandleMessage_Ping,
+ [IPCMSG_GETGLOBAL] = &HandleMessage_GetGlobalAttr,
+ [IPCMSG_SETGLOBAL] = &HandleMessage_SetGlobalAttr,
+
+ [IPCMSG_CREATEWIN] = &HandleMessage_CreateWindow,
+ [IPCMSG_CLOSEWIN] = &HandleMessage_DestroyWindow,
+ [IPCMSG_SETWINATTR] = &HandleMessage_SetWindowAttr,
+ [IPCMSG_GETWINATTR] = &HandleMessage_GetWindowAttr,
+ [IPCMSG_SENDIPC] = &HandleMessage_SendIPC, // Use the GUI server for low-bandwith IPC
+ [IPCMSG_GETWINBUF] = &HandleMessage_GetWindowBuffer,
+ [IPCMSG_DAMAGERECT] = &HandleMessage_DamageRect,
+ [IPCMSG_PUSHDATA] = &HandleMessage_PushData, // to a window's buffer
+ [IPCMSG_BLIT] = &HandleMessage_Blit, // Copy data from one part of the window to another
+ [IPCMSG_DRAWCTL] = &HandleMessage_DrawCtl, // Draw a control
+ [IPCMSG_DRAWTEXT] = &HandleMessage_DrawText, // Draw text
+ [IPCMSG_FILLRECT] = &HandleMessage_FillRect, // Fill a rectangle
+ [IPCMSG_DRAWRECT] = &HandleMessage_DrawRect, // Draw (outline) a rectangle
};
+
+void HandleMessage(CClient& client, CDeserialiser& message)
+{
+ const unsigned int num_commands = sizeof(message_handlers)/sizeof(IPC::MessageHandler_op_t*);
+ unsigned int command = message.ReadU8();
+ if( command >= num_commands ) {
+ // Drop, invalid command
+ _SysDebug("HandleMessage: Command %u is invalid (out of range for %u)", command, num_commands);
+ return ;
+ }
+
+ (message_handlers[command])(client, message);
+}
+
+CClientFailure::CClientFailure(std::string&& what):
+ m_what(what)
+{
+}
+const char *CClientFailure::what() const throw()
+{
+ return m_what.c_str();
+}
+CClientFailure::~CClientFailure() throw()
+{
+}
+
+}; // namespace IPC
+
+IIPCChannel::~IIPCChannel()
+{
+}
+
}; // namespace AxWin