1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "uiclient.h"
30 #include "args.h"
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <cx/hash_map.h>
35
36 #include "../ui/common/args.h"
37
38 #ifndef _WIN32
39
40 static UiMessageHandler *io;
41
42 static CxMap *msg_types;
43 static CxMap *objects;
44
45 void client_init(UiMessageHandler *handler) {
46 io = handler;
47
48 msg_types = cxHashMapCreateSimple(
CX_STORE_POINTERS);
49 cxMapPut(msg_types,
"window", msg_window);
50 cxMapPut(msg_types,
"sidebar_window", msg_window);
51 cxMapPut(msg_types,
"splitview_window", msg_window);
52 cxMapPut(msg_types,
"simple_window", msg_window);
53 cxMapPut(msg_types,
"show", msg_show);
54
55 cxMapPut(msg_types,
"vbox", msg_vbox);
56 cxMapPut(msg_types,
"hbox", msg_vbox);
57 cxMapPut(msg_types,
"grid", msg_vbox);
58 cxMapPut(msg_types,
"end", msg_end);
59 cxMapPut(msg_types,
"button", msg_button);
60 cxMapPut(msg_types,
"toggle", msg_togglebutton);
61
62 objects = cxHashMapCreateSimple(
CX_STORE_POINTERS);
63 }
64
65 static cxmutstr jsonobj_getstring(
const CxJsonValue *obj,
const char *name) {
66 CxJsonValue *value = cxJsonObjGet(obj, name);
67 if(value->type ==
CX_JSON_STRING) {
68 return value->value.string;
69 }
else {
70 return (cxmutstr){
NULL,
0 };
71 }
72 }
73
74 static UiBool jsonobj_getbool(
const CxJsonValue *obj,
const char *name,
int *error) {
75 CxJsonValue *value = cxJsonObjGet(obj, name);
76 if(value->type ==
CX_JSON_LITERAL) {
77 if(*error) {
78 *error =
0;
79 }
80 return value->value.literal ==
CX_JSON_TRUE ?
1 :
0;
81 }
else {
82 if(error) {
83 *error =
1;
84 }
85 return FALSE;
86 }
87 }
88
89
90
91
92 static int msg_received(
void *data) {
93 CxJsonValue *value = data;
94 if(client_handle_json(
NULL, value)) {
95 fprintf(stderr,
"Error: invalid json message\n");
96 }
97 cxJsonValueFree(value);
98 return 0;
99 }
100
101
102
103
104 void client_msg_received(cxstring msg) {
105
106 CxJson json;
107 cxJsonInit(&json,
NULL);
108
109 cxJsonFilln(&json, msg.ptr, msg.length);
110 CxJsonValue *value;
111 if(cxJsonNext(&json, &value) ==
CX_JSON_NO_ERROR && value) {
112
113 ui_call_mainthread(msg_received, value);
114 }
else {
115 fprintf(stderr,
"Error: invalid json message\n");
116 }
117 cxJsonDestroy(&json);
118 }
119
120 int client_handle_json(UiObject *obj,
const CxJsonValue *value) {
121 if(value->type !=
CX_JSON_OBJECT) {
122 return 1;
123 }
124
125 CxJsonValue *type = cxJsonObjGet(value,
"type");
126 if(!type || type->type !=
CX_JSON_STRING) {
127 return 1;
128 }
129
130 json_msg_handler handler = cxMapGet(msg_types, type->value.string);
131 if(!handler) {
132 return 1;
133 }
134
135 return handler(obj, value, type->value.string);
136 }
137
138 int client_handle_children(UiObject *parent,
const CxJsonValue *value) {
139 CxJsonValue *children = cxJsonObjGet(value,
"children");
140 if(children && children->type ==
CX_JSON_ARRAY) {
141 for(
int i=
0;i<children->value.array.array_size;i++) {
142 CxJsonValue *child = children->value.array.array[i];
143 if(client_handle_json(parent, child)) {
144 fprintf(stderr,
"Error: invalid child\n");
145 return 1;
146 }
147 }
148 }
149 return 0;
150 }
151
152 void client_add_obj_mapping(UiObject *obj, cxmutstr id) {
153 cxMapPut(objects, id, obj);
154
155 CxAllocator *a = ui_allocator(obj->ctx);
156
157 WindowData *wdata = cxMalloc(a,
sizeof(WindowData));
158 wdata->widgets = cxHashMapCreate(a,
CX_STORE_POINTERS,
128);
159 obj->window = wdata;
160 }
161
162 UiObject* client_get_mapped_obj(cxmutstr id) {
163 return cxMapGet(objects, id);
164 }
165
166 void client_reg_widget(UiObject *obj, cxmutstr id,
UIWIDGET w) {
167 WindowData *wdata = obj->window;
168 if(!wdata) {
169 fprintf(stderr,
"Error: missing obj window data\n");
170 return;
171 }
172 cxMapPut(wdata->widgets, id, w);
173 }
174
175 UIWIDGET client_get_widget(UiObject *obj, cxmutstr id) {
176 WindowData *wdata = obj->window;
177 if(!wdata) {
178 fprintf(stderr,
"Error: missing obj window data\n");
179 return NULL;
180 }
181 return cxMapGet(wdata->widgets, id);
182 }
183
184 static UiObject* get_msg_obj(UiObject *obj,
const CxJsonValue *value) {
185 if(obj) {
186 return obj;
187 }
188 CxJsonValue *obj_id = cxJsonObjGet(value,
"obj");
189 if(!obj_id || obj_id->type !=
CX_JSON_STRING) {
190 return NULL;
191 }
192 return client_get_mapped_obj(obj_id->value.string);
193 }
194
195 int msg_window(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
196 cxmutstr obj_id = jsonobj_getstring(value,
"obj");
197 cxmutstr id = jsonobj_getstring(value,
"id");
198 cxmutstr title = jsonobj_getstring(value,
"title");
199
200 if(!obj_id.ptr) {
201 return 1;
202 }
203 if(!id.ptr) {
204 return 1;
205 }
206
207 UiObject *obj;
208 if(!cx_strcmp(type,
"window")) {
209 obj = ui_window(title.ptr,
NULL);
210 }
else if(!cx_strcmp(type,
"sidebar_window")) {
211 obj = ui_sidebar_window(title.ptr,
NULL);
212 }
else if(!cx_strcmp(type,
"splitview_window")) {
213 int err;
214 bool sidebar = jsonobj_getbool(value,
"sidebar", &err);
215 if(err) {
216 return 1;
217 }
218 obj = ui_splitview_window(title.ptr, sidebar);
219 }
else if(!cx_strcmp(type,
"simple_window")) {
220 obj = ui_simple_window(title.ptr,
NULL);
221 }
222
223 client_add_obj_mapping(obj, obj_id);
224
225 if(obj->widget) {
226 client_reg_widget(obj, id, obj->widget);
227 }
228
229 return client_handle_children(obj, value);
230 }
231
232 int msg_show(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
233 UiObject *obj = client_get_mapped_obj(jsonobj_getstring(value,
"obj"));
234 if(!obj) {
235 return 1;
236 }
237 ui_show(obj);
238 return 0;
239 }
240
241 typedef UIWIDGET(*ctcreate_func)(UiObject *obj, UiContainerArgs *args);
242
243 static int msg_container(UiObject *parent,
const CxJsonValue *value, ctcreate_func create) {
244 CxJsonValue *args_value = cxJsonObjGet(value,
"args");
245 cxmutstr id = jsonobj_getstring(value,
"id");
246 if(!id.ptr) {
247 return 1;
248 }
249 UiObject *obj = get_msg_obj(parent, value);
250 if(!obj) {
251 return 1;
252 }
253
254 UiContainerArgs *args = json2container_args(args_value);
255 UIWIDGET w = create(obj, args);
256 ui_container_args_free(args);
257 client_reg_widget(obj, id, w);
258
259 return 0;
260 }
261
262 int msg_vbox(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
263 return msg_container(parent, value, ui_vbox_create);
264 }
265
266 int msg_hbox(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
267 return msg_container(parent, value, ui_hbox_create);
268 }
269
270 int msg_grid(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
271 return msg_container(parent, value, ui_grid_create);
272 }
273
274 int msg_end(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
275 UiObject *obj = get_msg_obj(parent, value);
276 if(!obj) {
277 return 1;
278 }
279 ui_end_new(obj);
280 return 0;
281 }
282
283 int msg_button(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
284 CxJsonValue *args_value = cxJsonObjGet(value,
"args");
285 cxmutstr id = jsonobj_getstring(value,
"id");
286 if(!id.ptr) {
287 return 1;
288 }
289 UiObject *obj = get_msg_obj(parent, value);
290 if(!obj) {
291 return 1;
292 }
293
294 UiButtonArgs *args = json2button_args(args_value);
295 UIWIDGET w = ui_button_create(obj, args);
296 ui_button_args_free(args);
297 client_reg_widget(obj, id, w);
298
299 return 0;
300 }
301
302 int msg_togglebutton(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
303 CxJsonValue *args_value = cxJsonObjGet(value,
"args");
304 cxmutstr id = jsonobj_getstring(value,
"id");
305 if(!id.ptr) {
306 return 1;
307 }
308 UiObject *obj = get_msg_obj(parent, value);
309 if(!obj) {
310 return 1;
311 }
312
313 CxJsonValue *button_type = cxJsonObjGet(value,
"button_type");
314 if(!button_type || button_type->type !=
CX_JSON_INTEGER) {
315 return 1;
316 }
317
318 CxJsonValue *val = cxJsonObjGet(value,
"value");
319 UiInteger *i =
NULL;
320 if(val && val->type ==
CX_JSON_STRING) {
321 i = ui_get_int_var(obj->ctx, val->value.string.ptr);
322 if(!i) {
323 i = ui_int_new(obj->ctx, val->value.string.ptr);
324 }
325 }
326
327 UiToggleArgs *args = json2toggle_args(args_value);
328 UIWIDGET w;
329 switch(button_type->value.integer) {
330 default: {
331 w = ui_togglebutton_create(obj, args);
332 break;
333 }
334 case 1: {
335 w = ui_checkbox_create(obj, args);
336 break;
337 }
338 case 2: {
339 w = ui_switch_create(obj, args);
340 break;
341 }
342 case 3: {
343 w = ui_radiobutton_create(obj, args);
344 break;
345 }
346 }
347 ui_toggle_args_free(args);
348 client_reg_widget(obj, id, w);
349
350 return 0;
351 }
352
353 #endif
354