Usermode/AxWin4 - Fixing ID lookups of windows and clients
[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         // allocate a client ID, and save
69         for( int i = 0; i < 100; i ++ )
70         {
71                 uint16_t id = giNextClient++;
72                 if(giNextClient == 0)   giNextClient = 1;
73                 auto r = glClients.insert( ::std::pair<uint16_t,CClient*>(id, &client) );
74                 if( r.second == true )
75                 {
76                         client.set_id(id);
77                         return;
78                 }
79         }
80         // Wut? 100 attempts and fail!
81         assert(!"Todo - Better way of handling client ID reuse");
82 }
83
84 CClient* GetClientByID(uint16_t id)
85 {
86         auto it = glClients.find(id);
87         return (it == glClients.end() ? nullptr : it->second);
88 }
89
90 void DeregisterClient(CClient& client)
91 {
92         glClients.erase( client.id() );
93 }
94
95
96 void SendMessage_NotifyDims(CClient& client, unsigned int NewW, unsigned int NewH)
97 {
98         _SysDebug("TODO: CClient::SendNotify_Dims");
99 }
100
101
102 void HandleMessage_Nop(CClient& client, CDeserialiser& message)
103 {
104         // Do nothing
105 }
106 void HandleMessage_Reply(CClient& client, CDeserialiser& message)
107 {
108         // Reply to a sent message
109         // - Not many messages need server-bound replies
110         int orig_command = message.ReadU8();
111         switch(orig_command)
112         {
113         case IPCMSG_PING:
114                 // Ping reply, mark client as still responding
115                 break;
116         default:
117                 // Unexpected reply
118                 break;
119         }
120 }
121
122 void HandleMessage_Ping(CClient& client, CDeserialiser& message)
123 {
124         // A client has asked for a ping, we pong them back
125         CSerialiser     reply;
126         reply.WriteU8(IPCMSG_REPLY);
127         reply.WriteU8(IPCMSG_PING);
128         client.SendMessage(reply);
129 }
130
131 void HandleMessage_GetGlobalAttr(CClient& client, CDeserialiser& message)
132 {
133         uint16_t        attr_id = message.ReadU16();
134         
135         CSerialiser     reply;
136         reply.WriteU8(IPCMSG_REPLY);
137         reply.WriteU8(IPCMSG_GETGLOBAL);
138         reply.WriteU16(attr_id);
139         
140         switch(attr_id)
141         {
142         case IPC_GLOBATTR_SCREENDIMS: {
143                 uint8_t screen_id = message.ReadU8();
144                 unsigned int w, h;
145                 gpCompositor->GetScreenDims(screen_id, &w, &h);
146                 reply.WriteU16( (w <= UINT16_MAX ? w : UINT16_MAX) );
147                 reply.WriteU16( (h <= UINT16_MAX ? h : UINT16_MAX) );
148                 break; }
149         case IPC_GLOBATTR_MAXAREA:
150                 assert(!"TODO: IPC_GLOBATTR_MAXAREA");
151                 break;
152         default:
153                 throw IPC::CClientFailure("Bad global attribute ID");
154         }
155         
156         client.SendMessage(reply);
157 }
158
159 void HandleMessage_SetGlobalAttr(CClient& client, CDeserialiser& message)
160 {
161         uint16_t        attr_id = message.ReadU16();
162         
163         switch(attr_id)
164         {
165         case IPC_GLOBATTR_SCREENDIMS:
166                 // Setting readonly
167                 break;
168         case IPC_GLOBATTR_MAXAREA:
169                 assert(!"TODO: IPC_GLOBATTR_MAXAREA");
170                 break;
171         default:
172                 throw IPC::CClientFailure("Bad global attribute ID");
173         }
174 }
175
176 void HandleMessage_CreateWindow(CClient& client, CDeserialiser& message)
177 {
178         uint16_t        new_id = message.ReadU16();
179         //uint16_t      parent_id = message.ReadU16();
180         //CWindow* parent = client.GetWindow( parent_id );
181         ::std::string   name = message.ReadString();
182         
183         ::_SysDebug("_CreateWindow: (%i, '%s')", new_id, name.c_str());
184         client.SetWindow( new_id, new CWindow(*gpCompositor, client, name, new_id) );
185 }
186
187 void HandleMessage_DestroyWindow(CClient& client, CDeserialiser& message)
188 {
189         uint16_t        win_id = message.ReadU16();
190         _SysDebug("_DestroyWindow: (%i)", win_id);
191         
192         CWindow*        win = client.GetWindow(win_id);
193         if(!win) {
194                 throw IPC::CClientFailure("_DestroyWindow: Bad window");
195         }
196         client.SetWindow(win_id, 0);    
197         
198         // TODO: Directly inform compositor?
199         delete win;
200 }
201
202 void HandleMessage_SetWindowAttr(CClient& client, CDeserialiser& message)
203 {
204         uint16_t        win_id = message.ReadU16();
205         uint16_t        attr_id = message.ReadU16();
206         _SysDebug("_SetWindowAttr: (Win=%i, ID=%i)", win_id, attr_id);
207         
208         CWindow*        win = client.GetWindow(win_id);
209         if(!win) {
210                 throw IPC::CClientFailure("_SetWindowAttr - Bad window");
211         }
212         
213         switch(attr_id)
214         {
215         case IPC_WINATTR_DIMENSIONS: {
216                 uint16_t new_w = message.ReadU16();
217                 uint16_t new_h = message.ReadU16();
218                 win->Resize(new_w, new_h);
219                 break; }
220         case IPC_WINATTR_POSITION: {
221                 int16_t new_x = message.ReadS16();
222                 int16_t new_y = message.ReadS16();
223                 win->Move(new_x, new_y);
224                 break; }
225         case IPC_WINATTR_SHOW:
226                 win->Show( message.ReadU8() != 0 );
227                 break;
228         case IPC_WINATTR_FLAGS:
229                 win->SetFlags( message.ReadU8() );      // TODO: U8? why so small?
230                 break;
231         case IPC_WINATTR_TITLE:
232                 assert(!"TODO: IPC_WINATTR_TITLE");
233                 break;
234         default:
235                 _SysDebug("HandleMessage_SetWindowAttr - Bad attr %u", attr_id);
236                 throw IPC::CClientFailure("Bad window attr");
237         }
238 }
239
240 void HandleMessage_GetWindowAttr(CClient& client, CDeserialiser& message)
241 {
242         assert(!"TODO HandleMessage_GetWindowAttr");
243 }
244
245 void HandleMessage_SendIPC(CClient& client, CDeserialiser& message)
246 {
247         assert(!"TODO HandleMessage_SendIPC");
248 }
249
250 void HandleMessage_GetWindowBuffer(CClient& client, CDeserialiser& message)
251 {
252         uint16_t        win_id = message.ReadU16();
253         _SysDebug("_GetWindowBuffer: (%i)", win_id);
254         
255         CWindow*        win = client.GetWindow(win_id);
256         if(!win) {
257                 throw IPC::CClientFailure("_PushData: Bad window");
258         }
259         
260         uint64_t handle = win->m_surface.GetSHMHandle();
261         
262         CSerialiser     reply;
263         reply.WriteU8(IPCMSG_REPLY);
264         reply.WriteU8(IPCMSG_GETWINBUF);
265         reply.WriteU16(win_id);
266         reply.WriteU64(handle);
267         client.SendMessage(reply);
268 }
269
270 void HandleMessage_DamageRect(CClient& client, CDeserialiser& message)
271 {
272         uint16_t        winid = message.ReadU16();
273         uint16_t        x = message.ReadU16();
274         uint16_t        y = message.ReadU16();
275         uint16_t        w = message.ReadU16();
276         uint16_t        h = message.ReadU16();
277         
278         _SysDebug("_DamageRect: (%i %i,%i %ix%i)", winid, x, y, w, h);
279         
280         CWindow*        win = client.GetWindow(winid);
281         if(!win) {
282                 throw IPC::CClientFailure("_PushData: Bad window");
283         }
284         
285         CRect   area(x,y,w,h);
286         
287         win->Repaint(area);
288 }
289
290 void HandleMessage_PushData(CClient& client, CDeserialiser& message)
291 {
292         uint16_t        win_id = message.ReadU16();
293         uint16_t        x = message.ReadU16();
294         uint16_t        y = message.ReadU16();
295         uint16_t        w = message.ReadU16();
296         uint16_t        h = message.ReadU16();
297         _SysDebug("_PushData: (%i, (%i,%i) %ix%i)", win_id, x, y, w, h);
298         
299         CWindow*        win = client.GetWindow(win_id);
300         if(!win) {
301                 throw IPC::CClientFailure("_PushData: Bad window");
302         }
303         
304         for( unsigned int row = 0; row < h; row ++ )
305         {
306                 const ::std::vector<uint8_t> scanline_data = message.ReadBuffer();
307                 if( scanline_data.size() != w * 4 ) {
308                         _SysDebug("ERROR _PushData: Scanline buffer size mismatch (%i,%i)",
309                                 scanline_data.size(), w*4);
310                         continue ;
311                 }
312                 win->DrawScanline(y+row, x, w, scanline_data.data());
313         }
314 }
315 void HandleMessage_Blit(CClient& client, CDeserialiser& message)
316 {
317         assert(!"TODO HandleMessage_Blit");
318 }
319 void HandleMessage_DrawCtl(CClient& client, CDeserialiser& message)
320 {
321         uint16_t        win_id = message.ReadU16();
322         uint16_t        x = message.ReadU16();
323         uint16_t        y = message.ReadU16();
324         uint16_t        w = message.ReadU16();
325         uint16_t        h = message.ReadU16();
326         uint16_t        ctrl_id = message.ReadU16();
327         uint16_t        frame = message.ReadU16();
328         _SysDebug("_DrawCtl: (%i, (%i,%i) %ix%i Ctl%i frame?=0x%04x)", win_id, x, y, w, h, ctrl_id, frame);
329         
330         CWindow*        win = client.GetWindow(win_id);
331         if(!win) {
332                 throw IPC::CClientFailure("_DrawCtl: Bad window");
333         }
334         
335         const CControl* ctrl = CControl::GetByID(ctrl_id);
336         if(!ctrl) {
337                 throw IPC::CClientFailure("_DrawCtl: Invalid control ID");
338         }
339         
340         CRect   area(x,y,w,h);
341         ctrl->Render(win->m_surface, area);
342 }
343 void HandleMessage_DrawText(CClient& client, CDeserialiser& message)
344 {
345         uint16_t        win_id = message.ReadU16();
346         uint16_t        x = message.ReadU16();
347         uint16_t        y = message.ReadU16();
348         uint16_t        w = message.ReadU16();
349         uint16_t        h = message.ReadU16();
350         uint16_t        font = message.ReadU16();
351         ::std::string   str = message.ReadString();
352         _SysDebug("_DrawText: (%i (%i,%i) %ix%i Font%i \"%s\")", win_id, x, y, w, h, font, str.c_str());
353         
354         CWindow*        win = client.GetWindow(win_id);
355         if(!win) {
356                 throw IPC::CClientFailure("_DrawText: Bad window");
357         }
358         
359         // 1. Get font from client structure
360         //CFont& font = client.GetFont(font_id);
361         
362         // 2. Render
363         //CRect area(x, y, w, h);
364         //font->Render(win->m_surface, area, str, h);
365         
366         _SysDebug("TODO: HandleMessage_DrawText");
367 }
368
369 typedef void    MessageHandler_op_t(CClient& client, CDeserialiser& message);
370
371 MessageHandler_op_t     *message_handlers[] = {
372         [IPCMSG_NULL]       = &HandleMessage_Nop,
373         [IPCMSG_REPLY]      = &HandleMessage_Reply,
374         [IPCMSG_PING]       = &HandleMessage_Ping,
375         [IPCMSG_GETGLOBAL]  = &HandleMessage_GetGlobalAttr,
376         [IPCMSG_SETGLOBAL]  = &HandleMessage_SetGlobalAttr,
377         
378         [IPCMSG_CREATEWIN]  = &HandleMessage_CreateWindow,
379         [IPCMSG_CLOSEWIN]   = &HandleMessage_DestroyWindow,
380         [IPCMSG_SETWINATTR] = &HandleMessage_SetWindowAttr,
381         [IPCMSG_GETWINATTR] = &HandleMessage_GetWindowAttr,
382         [IPCMSG_SENDIPC]    = &HandleMessage_SendIPC,   // Use the GUI server for low-bandwith IPC
383         [IPCMSG_GETWINBUF]  = &HandleMessage_GetWindowBuffer,
384         [IPCMSG_DAMAGERECT] = &HandleMessage_DamageRect,
385         [IPCMSG_PUSHDATA]   = &HandleMessage_PushData,  // to a window's buffer
386         [IPCMSG_BLIT]       = &HandleMessage_Blit,      // Copy data from one part of the window to another
387         [IPCMSG_DRAWCTL]    = &HandleMessage_DrawCtl,   // Draw a control
388         [IPCMSG_DRAWTEXT]   = &HandleMessage_DrawText,  // Draw text
389 };
390
391 void HandleMessage(CClient& client, CDeserialiser& message)
392 {
393         unsigned int command = message.ReadU8();
394         if( command >= sizeof(message_handlers)/sizeof(IPC::MessageHandler_op_t*) ) {
395                 // Drop, invalid command
396                 return ;
397         }
398         
399         (message_handlers[command])(client, message);
400 }
401
402 CClientFailure::CClientFailure(std::string&& what):
403         m_what(what)
404 {
405 }
406 const char *CClientFailure::what() const throw()
407 {
408         return m_what.c_str();
409 }
410 CClientFailure::~CClientFailure() throw()
411 {
412 }
413
414 };      // namespace IPC
415
416 IIPCChannel::~IIPCChannel()
417 {
418 }
419
420 };      // namespace AxWin
421

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