Usermode/AxWin4 - Send mouse/keyboard events to client
[tpg/acess2.git] / Usermode / Applications / axwin4_src / Server / ipc.cpp
1 /*
2  * Acess2 GUI v4
3  * - By John Hodge (thePowersGang)
4  *
5  * ipc.cpp
6  * - Client-Server communication (dispatch)
7  */
8 #define __STDC_LIMIT_MACROS
9 #include <ipc.hpp>
10 #include <list>
11 #include <IIPCChannel.hpp>
12 #include <algorithm>
13 #include <CClient.hpp>
14 #include <serialisation.hpp>
15 #include <ipc_proto.hpp>
16 #include <CCompositor.hpp>
17 extern "C" {
18 #include <assert.h>
19 };
20 #include <CIPCChannel_AcessIPCPipe.hpp>
21 #include <draw_control.hpp>
22
23 namespace AxWin {
24 namespace IPC {
25
26 CCompositor*    gpCompositor;
27 ::std::list<IIPCChannel*>       glChannels;
28 ::std::map<uint16_t,CClient*>   glClients;
29 uint16_t        giNextClient = 1;
30
31 void Initialise(const CConfigIPC& config, CCompositor& compositor)
32 {
33         gpCompositor = &compositor;
34         
35         ::std::string pipe_basepath = "axwin4";
36         glChannels.push_back( new CIPCChannel_AcessIPCPipe( pipe_basepath ) );
37
38         //glChannels.push_back( new CIPCChannel_TCP("0.0.0.0:2100") );
39         
40         //for( auto channel : config.m_channels )
41         //{
42         //      channels.push_back(  );
43         //}
44 }
45
46 int FillSelect(fd_set& rfds)
47 {
48         int ret = 0;
49         for( const auto channel : glChannels )
50         {
51                 assert(channel);
52                 ret = ::std::max(ret, channel->FillSelect(rfds));
53         }
54         return ret;
55 }
56
57 void HandleSelect(const fd_set& rfds)
58 {
59         for( const auto channel : glChannels )
60         {
61                 assert(channel);
62                 channel->HandleSelect(rfds);
63         }
64 }
65
66 void RegisterClient(CClient& client)
67 {
68         _SysDebug("RegisterClient(&client=%p)", &client);
69         // allocate a client ID, and save
70         for( int i = 0; i < 100; i ++ )
71         {
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 )
76                 {
77                         client.set_id(id);
78                         return;
79                 }
80         }
81         // Wut? 100 attempts and fail!
82         assert(!"Todo - Better way of handling client ID reuse");
83 }
84
85 CClient* GetClientByID(uint16_t id)
86 {
87         auto it = glClients.find(id);
88         if(it == glClients.end()) {
89                 //_SysDebug("Client %i not registered", id);
90                 return nullptr;
91         }
92         else {
93                 //_SysDebug("Client %i %i = %p", id, it->first, it->second);
94                 return it->second;
95         }
96 }
97
98 void DeregisterClient(CClient& client)
99 {
100         glClients.erase( client.id() );
101 }
102
103
104 void SendMessage_NotifyDims(CClient& client, unsigned int WinID, unsigned int NewW, unsigned int NewH)
105 {
106         _SysDebug("TODO: IPC::SendMessage_NotifyDims");
107 }
108 void SendMessage_MouseButton(CClient& client, unsigned int WinID, unsigned int X, unsigned int Y, uint8_t Button, bool Pressed)
109 {
110         CSerialiser     msg;
111         msg.WriteU8(IPCMSG_INPUTEVENT);
112         msg.WriteU8(IPC_INEV_MOUSEBTN);
113         msg.WriteU16(WinID);
114         msg.WriteU16(X);
115         msg.WriteU16(Y);
116         msg.WriteU8(Button);
117         msg.WriteU8(Pressed ? 0 : 1);
118         client.SendMessage(msg);
119 }
120 void SendMessage_MouseMove(CClient& client, unsigned int WinID, unsigned int X, unsigned int Y)
121 {
122         _SysDebug("TODO: IPC::SendMessage_MouseButton");
123 }
124 void SendMessage_KeyEvent(CClient& client, unsigned int WinID, uint32_t KeySym, bool Pressed, const char *Translated)
125 {
126         CSerialiser     msg;
127         msg.WriteU8(IPCMSG_INPUTEVENT);
128         msg.WriteU8(IPC_INEV_KEYBOARD);
129         msg.WriteU16(WinID);
130         msg.WriteU16(KeySym);
131         msg.WriteU8(Pressed ? 0 : 1);
132         msg.WriteString(Translated);
133         client.SendMessage(msg);
134 }
135
136
137 void HandleMessage_Nop(CClient& client, CDeserialiser& message)
138 {
139         // Do nothing
140 }
141 void HandleMessage_Reply(CClient& client, CDeserialiser& message)
142 {
143         // Reply to a sent message
144         // - Not many messages need server-bound replies
145         int orig_command = message.ReadU8();
146         switch(orig_command)
147         {
148         case IPCMSG_PING:
149                 // Ping reply, mark client as still responding
150                 break;
151         default:
152                 // Unexpected reply
153                 break;
154         }
155 }
156
157 void HandleMessage_Ping(CClient& client, CDeserialiser& message)
158 {
159         // A client has asked for a ping, we pong them back
160         CSerialiser     reply;
161         reply.WriteU8(IPCMSG_REPLY);
162         reply.WriteU8(IPCMSG_PING);
163         client.SendMessage(reply);
164 }
165
166 void HandleMessage_GetGlobalAttr(CClient& client, CDeserialiser& message)
167 {
168         uint16_t        attr_id = message.ReadU16();
169         
170         CSerialiser     reply;
171         reply.WriteU8(IPCMSG_REPLY);
172         reply.WriteU8(IPCMSG_GETGLOBAL);
173         reply.WriteU16(attr_id);
174         
175         switch(attr_id)
176         {
177         case IPC_GLOBATTR_SCREENDIMS: {
178                 uint8_t screen_id = message.ReadU8();
179                 unsigned int w, h;
180                 gpCompositor->GetScreenDims(screen_id, &w, &h);
181                 reply.WriteU16( (w <= UINT16_MAX ? w : UINT16_MAX) );
182                 reply.WriteU16( (h <= UINT16_MAX ? h : UINT16_MAX) );
183                 break; }
184         case IPC_GLOBATTR_MAXAREA:
185                 assert(!"TODO: IPC_GLOBATTR_MAXAREA");
186                 break;
187         default:
188                 throw IPC::CClientFailure("Bad global attribute ID");
189         }
190         
191         client.SendMessage(reply);
192 }
193
194 void HandleMessage_SetGlobalAttr(CClient& client, CDeserialiser& message)
195 {
196         uint16_t        attr_id = message.ReadU16();
197         
198         switch(attr_id)
199         {
200         case IPC_GLOBATTR_SCREENDIMS:
201                 // Setting readonly
202                 break;
203         case IPC_GLOBATTR_MAXAREA:
204                 assert(!"TODO: IPC_GLOBATTR_MAXAREA");
205                 break;
206         default:
207                 throw IPC::CClientFailure("Bad global attribute ID");
208         }
209 }
210
211 void HandleMessage_CreateWindow(CClient& client, CDeserialiser& message)
212 {
213         uint16_t        new_id = message.ReadU16();
214         //uint16_t      parent_id = message.ReadU16();
215         //CWindow* parent = client.GetWindow( parent_id );
216         ::std::string   name = message.ReadString();
217         
218         ::_SysDebug("_CreateWindow: (%i, '%s')", new_id, name.c_str());
219         client.SetWindow( new_id, new CWindow(*gpCompositor, client, name, new_id) );
220 }
221
222 void HandleMessage_DestroyWindow(CClient& client, CDeserialiser& message)
223 {
224         uint16_t        win_id = message.ReadU16();
225         _SysDebug("_DestroyWindow: (%i)", win_id);
226         
227         CWindow*        win = client.GetWindow(win_id);
228         if(!win) {
229                 throw IPC::CClientFailure("_DestroyWindow: Bad window");
230         }
231         client.SetWindow(win_id, 0);    
232         
233         // TODO: Directly inform compositor?
234         delete win;
235 }
236
237 void HandleMessage_SetWindowAttr(CClient& client, CDeserialiser& message)
238 {
239         uint16_t        win_id = message.ReadU16();
240         uint16_t        attr_id = message.ReadU16();
241         _SysDebug("_SetWindowAttr: (Win=%i, ID=%i)", win_id, attr_id);
242         
243         CWindow*        win = client.GetWindow(win_id);
244         if(!win) {
245                 throw IPC::CClientFailure("_SetWindowAttr - Bad window");
246         }
247         
248         switch(attr_id)
249         {
250         case IPC_WINATTR_DIMENSIONS: {
251                 uint16_t new_w = message.ReadU16();
252                 uint16_t new_h = message.ReadU16();
253                 win->Resize(new_w, new_h);
254                 break; }
255         case IPC_WINATTR_POSITION: {
256                 int16_t new_x = message.ReadS16();
257                 int16_t new_y = message.ReadS16();
258                 win->Move(new_x, new_y);
259                 break; }
260         case IPC_WINATTR_SHOW:
261                 win->Show( message.ReadU8() != 0 );
262                 break;
263         case IPC_WINATTR_FLAGS:
264                 win->SetFlags( message.ReadU8() );      // TODO: U8? why so small?
265                 break;
266         case IPC_WINATTR_TITLE:
267                 assert(!"TODO: IPC_WINATTR_TITLE");
268                 break;
269         default:
270                 _SysDebug("HandleMessage_SetWindowAttr - Bad attr %u", attr_id);
271                 throw IPC::CClientFailure("Bad window attr");
272         }
273 }
274
275 void HandleMessage_GetWindowAttr(CClient& client, CDeserialiser& message)
276 {
277         assert(!"TODO HandleMessage_GetWindowAttr");
278 }
279
280 void HandleMessage_SendIPC(CClient& client, CDeserialiser& message)
281 {
282         assert(!"TODO HandleMessage_SendIPC");
283 }
284
285 void HandleMessage_GetWindowBuffer(CClient& client, CDeserialiser& message)
286 {
287         uint16_t        win_id = message.ReadU16();
288         _SysDebug("_GetWindowBuffer: (%i)", win_id);
289         
290         CWindow*        win = client.GetWindow(win_id);
291         if(!win) {
292                 throw IPC::CClientFailure("_PushData: Bad window");
293         }
294         
295         uint64_t handle = win->m_surface.GetSHMHandle();
296         
297         CSerialiser     reply;
298         reply.WriteU8(IPCMSG_REPLY);
299         reply.WriteU8(IPCMSG_GETWINBUF);
300         reply.WriteU16(win_id);
301         reply.WriteU64(handle);
302         client.SendMessage(reply);
303 }
304
305 void HandleMessage_DamageRect(CClient& client, CDeserialiser& message)
306 {
307         uint16_t        winid = message.ReadU16();
308         uint16_t        x = message.ReadU16();
309         uint16_t        y = message.ReadU16();
310         uint16_t        w = message.ReadU16();
311         uint16_t        h = message.ReadU16();
312         
313         _SysDebug("_DamageRect: (%i %i,%i %ix%i)", winid, x, y, w, h);
314         
315         CWindow*        win = client.GetWindow(winid);
316         if(!win) {
317                 throw IPC::CClientFailure("_PushData: Bad window");
318         }
319         
320         CRect   area(x,y,w,h);
321         
322         win->Repaint(area);
323 }
324
325 void HandleMessage_PushData(CClient& client, CDeserialiser& message)
326 {
327         uint16_t        win_id = message.ReadU16();
328         uint16_t        x = message.ReadU16();
329         uint16_t        y = message.ReadU16();
330         uint16_t        w = message.ReadU16();
331         uint16_t        h = message.ReadU16();
332         _SysDebug("_PushData: (%i, (%i,%i) %ix%i)", win_id, x, y, w, h);
333         
334         CWindow*        win = client.GetWindow(win_id);
335         if(!win) {
336                 throw IPC::CClientFailure("_PushData: Bad window");
337         }
338         
339         for( unsigned int row = 0; row < h; row ++ )
340         {
341                 const ::std::vector<uint8_t> scanline_data = message.ReadBuffer();
342                 if( scanline_data.size() != w * 4 ) {
343                         _SysDebug("ERROR _PushData: Scanline buffer size mismatch (%i,%i)",
344                                 scanline_data.size(), w*4);
345                         continue ;
346                 }
347                 win->DrawScanline(y+row, x, w, scanline_data.data());
348         }
349 }
350 void HandleMessage_Blit(CClient& client, CDeserialiser& message)
351 {
352         assert(!"TODO HandleMessage_Blit");
353 }
354 void HandleMessage_DrawCtl(CClient& client, CDeserialiser& message)
355 {
356         uint16_t        win_id = message.ReadU16();
357         uint16_t        x = message.ReadU16();
358         uint16_t        y = message.ReadU16();
359         uint16_t        w = message.ReadU16();
360         uint16_t        h = message.ReadU16();
361         uint16_t        ctrl_id = message.ReadU16();
362         uint16_t        frame = message.ReadU16();
363         _SysDebug("_DrawCtl: (%i, (%i,%i) %ix%i Ctl%i frame?=0x%04x)", win_id, x, y, w, h, ctrl_id, frame);
364         
365         CWindow*        win = client.GetWindow(win_id);
366         if(!win) {
367                 throw IPC::CClientFailure("_DrawCtl: Bad window");
368         }
369         
370         const CControl* ctrl = CControl::GetByID(ctrl_id);
371         if(!ctrl) {
372                 throw IPC::CClientFailure("_DrawCtl: Invalid control ID");
373         }
374         
375         CRect   area(x,y,w,h);
376         ctrl->Render(win->m_surface, area);
377 }
378 void HandleMessage_DrawText(CClient& client, CDeserialiser& message)
379 {
380         uint16_t        win_id = message.ReadU16();
381         uint16_t        x = message.ReadU16();
382         uint16_t        y = message.ReadU16();
383         uint16_t        w = message.ReadU16();
384         uint16_t        h = message.ReadU16();
385         uint16_t        font = message.ReadU16();
386         ::std::string   str = message.ReadString();
387         _SysDebug("_DrawText: (%i (%i,%i) %ix%i Font%i \"%s\")", win_id, x, y, w, h, font, str.c_str());
388         
389         CWindow*        win = client.GetWindow(win_id);
390         if(!win) {
391                 throw IPC::CClientFailure("_DrawText: Bad window");
392         }
393         
394         // 1. Get font from client structure
395         //CFont& font = client.GetFont(font_id);
396         
397         // 2. Render
398         //CRect area(x, y, w, h);
399         //font->Render(win->m_surface, area, str, h);
400         
401         _SysDebug("TODO: HandleMessage_DrawText");
402 }
403
404 typedef void    MessageHandler_op_t(CClient& client, CDeserialiser& message);
405
406 MessageHandler_op_t     *message_handlers[] = {
407         [IPCMSG_NULL]       = &HandleMessage_Nop,
408         [IPCMSG_REPLY]      = &HandleMessage_Reply,
409         [IPCMSG_PING]       = &HandleMessage_Ping,
410         [IPCMSG_GETGLOBAL]  = &HandleMessage_GetGlobalAttr,
411         [IPCMSG_SETGLOBAL]  = &HandleMessage_SetGlobalAttr,
412         
413         [IPCMSG_CREATEWIN]  = &HandleMessage_CreateWindow,
414         [IPCMSG_CLOSEWIN]   = &HandleMessage_DestroyWindow,
415         [IPCMSG_SETWINATTR] = &HandleMessage_SetWindowAttr,
416         [IPCMSG_GETWINATTR] = &HandleMessage_GetWindowAttr,
417         [IPCMSG_SENDIPC]    = &HandleMessage_SendIPC,   // Use the GUI server for low-bandwith IPC
418         [IPCMSG_GETWINBUF]  = &HandleMessage_GetWindowBuffer,
419         [IPCMSG_DAMAGERECT] = &HandleMessage_DamageRect,
420         [IPCMSG_PUSHDATA]   = &HandleMessage_PushData,  // to a window's buffer
421         [IPCMSG_BLIT]       = &HandleMessage_Blit,      // Copy data from one part of the window to another
422         [IPCMSG_DRAWCTL]    = &HandleMessage_DrawCtl,   // Draw a control
423         [IPCMSG_DRAWTEXT]   = &HandleMessage_DrawText,  // Draw text
424 };
425
426 void HandleMessage(CClient& client, CDeserialiser& message)
427 {
428         unsigned int command = message.ReadU8();
429         if( command >= sizeof(message_handlers)/sizeof(IPC::MessageHandler_op_t*) ) {
430                 // Drop, invalid command
431                 return ;
432         }
433         
434         (message_handlers[command])(client, message);
435 }
436
437 CClientFailure::CClientFailure(std::string&& what):
438         m_what(what)
439 {
440 }
441 const char *CClientFailure::what() const throw()
442 {
443         return m_what.c_str();
444 }
445 CClientFailure::~CClientFailure() throw()
446 {
447 }
448
449 };      // namespace IPC
450
451 IIPCChannel::~IIPCChannel()
452 {
453 }
454
455 };      // namespace AxWin
456

UCC git Repository :: git.ucc.asn.au