PageRenderTime 39ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/gtkNode/src/gtkNode_marshal.c

https://github.com/bmizerany/jungerl
C | 573 lines | 445 code | 84 blank | 44 comment | 58 complexity | be8f61311ff046602885cda4ebfe971b MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, AGPL-1.0
  1. #include "gtkNode.h"
  2. #include <string.h>
  3. #include <stdlib.h>
  4. static void hash_init() {
  5. extern GHashTable* ghash;
  6. if ( ! ghash ) ghash = g_hash_table_new(g_str_hash, g_str_equal);
  7. }
  8. void hash_insert(gchar* key, void* value) {
  9. extern GHashTable* ghash;
  10. hash_init();
  11. g_hash_table_insert(ghash, (gpointer) g_strdup(key), (gpointer) value);
  12. }
  13. void* hash_lookup(gchar* key) {
  14. extern GHashTable* ghash;
  15. hash_init();
  16. return (void*) g_hash_table_lookup(ghash, (gconstpointer) key);
  17. }
  18. static void ghFunc(gpointer key,gpointer value,gpointer user_data){
  19. g_message("hash_foreach %s %d", (gchar*) key, value);
  20. }
  21. static void hash_printall() {
  22. extern GHashTable* ghash;
  23. hash_init();
  24. g_hash_table_foreach(ghash, ghFunc, NULL);
  25. }
  26. /***************************************************************************/
  27. static char* get_type_name(const gchar* name) {
  28. char c;
  29. static char str[100];
  30. int i = 1;
  31. int ii = 1;
  32. str[0] = tolower(name[0]);
  33. while ( c = name[i++] ){
  34. if ( isupper(c) ) {
  35. str[ii++] = '_';
  36. str[ii++] = tolower(c);
  37. }else{
  38. str[ii++] = c;
  39. }
  40. }
  41. str[ii] = 0;
  42. return strcat(str,"_get_type");
  43. }
  44. GType gn_GType_from_name(const gchar* name) {
  45. extern GModule *gmod;
  46. GType (*func)(void);
  47. GType gtp;
  48. char* tname;
  49. /* is this type registered? */
  50. if ( (gtp = g_type_from_name(name) ) )
  51. return gtp;
  52. /* try to instantiate the type */
  53. tname = get_type_name(name);
  54. g_message("tname :%s:\n", tname);
  55. if ( g_module_symbol(gmod, tname, (gpointer *)&func ) )
  56. if ( (gtp = (*func)() ) )
  57. return gtp;
  58. /* no dice... */
  59. return (GType)NULL;
  60. }
  61. /***************************************************************************/
  62. /* wrap all answers in this */
  63. /* {{self(),reply|signal|error|handshake},...} */
  64. /***************************************************************************/
  65. void gn_wrap_ans(char* tag, ei_x_buff* xbuf) {
  66. extern ei_cnode ec;
  67. ei_x_encode_tuple_header(xbuf,2);
  68. ei_x_encode_tuple_header(xbuf,2);
  69. ei_x_encode_pid(xbuf, ei_self(&ec));
  70. ei_x_encode_atom(xbuf, tag);
  71. }
  72. void gn_wrap_reply(char* tag, ei_x_buff* xbuf) {
  73. ei_x_encode_tuple_header(xbuf,2);
  74. ei_x_encode_atom(xbuf, tag);
  75. }
  76. /***************************************************************************/
  77. /* error tuple builders */
  78. /***************************************************************************/
  79. /* {{Node,error}, {Err,...}} */
  80. void gn_enc_2_error(ei_x_buff *xbuf, char *err) {
  81. gn_wrap_reply("error", xbuf);
  82. ei_x_encode_tuple_header(xbuf,2);
  83. ei_x_encode_atom(xbuf, err);
  84. }
  85. /* {{Node,error}, Err} */
  86. void gn_enc_1_error(ei_x_buff *xbuf, char *err) {
  87. gn_wrap_reply("error", xbuf);
  88. ei_x_encode_atom(xbuf, err);
  89. }
  90. /***************************************************************************/
  91. /* marshal return values from gtk calls */
  92. /* {{Node,reply}, ...} */
  93. /***************************************************************************/
  94. void gn_put_tuple(ei_x_buff *xbuf, int N) {
  95. gn_wrap_reply("ok", xbuf);
  96. g_assert( ! ei_x_encode_tuple_header(xbuf,N));
  97. }
  98. void gn_put_void(ei_x_buff *xbuf) {
  99. gn_wrap_reply("ok", xbuf);
  100. g_assert( ! ei_x_encode_atom(xbuf, "void") );
  101. }
  102. void gn_put_pid(ei_x_buff *xbuf, erlang_pid *p) {
  103. gn_wrap_reply("ok", xbuf);
  104. g_assert( ! ei_x_encode_pid(xbuf, p) );
  105. }
  106. void gn_put_boolean(ei_x_buff *xbuf, int i) {
  107. gn_wrap_reply("ok", xbuf);
  108. g_assert( ! ei_x_encode_boolean(xbuf, i) );
  109. }
  110. void gn_put_double(ei_x_buff *xbuf, double d) {
  111. gn_wrap_reply("ok", xbuf);
  112. g_assert( ! ei_x_encode_double(xbuf, d) );
  113. }
  114. void gn_put_longlong(ei_x_buff *xbuf, long long l) {
  115. gn_wrap_reply("ok", xbuf);
  116. g_assert( ! ei_x_encode_longlong(xbuf, l) );
  117. }
  118. void gn_put_ulonglong(ei_x_buff *xbuf, unsigned long long l) {
  119. gn_wrap_reply("ok", xbuf);
  120. g_assert( ! ei_x_encode_ulonglong(xbuf, l) );
  121. }
  122. void gn_put_string(ei_x_buff *xbuf, char *p) {
  123. gn_wrap_reply("ok", xbuf);
  124. g_assert( ! ei_x_encode_string(xbuf, p) );
  125. }
  126. void gn_put_object(ei_x_buff *xbuf, GObject *w) {
  127. gchar bf[24];
  128. g_assert( (sprintf(bf,"%d", (long)w) < sizeof(bf)) );
  129. hash_insert(bf, (void*)w);
  130. gn_wrap_reply("ok", xbuf);
  131. g_assert( ! ei_x_encode_atom(xbuf, bf));
  132. }
  133. /* if GLib decides to free a struct we're hosed */
  134. /* i think one could rig up some freeing callback and */
  135. /*remove the pointer from the hash, but i'm not sure how */
  136. void gn_put_struct(ei_x_buff *xbuf, char *type, void *struct_p) {
  137. gchar key[200];
  138. gchar name[24];
  139. g_assert( (sprintf(name,"%d", (long)struct_p) < sizeof(name)) );
  140. g_assert( (strlen(type)+sizeof(name)+4) < sizeof(key) );
  141. memcpy(key, type, strlen(type)+1);
  142. strcat(key, "-");
  143. strcat(key, name);
  144. g_assert( hash_lookup(key) == NULL );
  145. hash_insert(key, struct_p);
  146. gn_wrap_reply("ok", xbuf);
  147. g_assert( ! ei_x_encode_atom(xbuf, name));
  148. }
  149. void gn_put_enum(ei_x_buff *xbuf, char* type_name, gint enum_val) {
  150. char buf[100];
  151. gn_wrap_reply("ok", xbuf);
  152. g_assert( gn_get_enum_name(type_name, enum_val, buf) );
  153. g_assert( ! ei_x_encode_atom(xbuf, buf));
  154. }
  155. void gn_put_flags(ei_x_buff *xbuf, char* type_name, guint flags) {
  156. GType gtyp;
  157. GFlagsClass* fclass;
  158. GFlagsValue* fval;
  159. gn_wrap_reply("ok", xbuf);
  160. g_assert( (gtyp = gn_GType_from_name(type_name)));
  161. g_assert(G_TYPE_IS_FLAGS(gtyp));
  162. fclass = g_type_class_ref(gtyp);
  163. while (flags) {
  164. fval = g_flags_get_first_value(fclass,flags);
  165. flags = flags & ~fval->value;
  166. g_assert( ! ei_x_encode_list_header(xbuf, 1) );
  167. g_assert( ! ei_x_encode_atom(xbuf, fval->value_name) );
  168. }
  169. g_assert( ! ei_x_encode_empty_list(xbuf));
  170. g_type_class_unref(fclass);
  171. }
  172. /***************************************************************************/
  173. /* marshalling erlang -> gtk */
  174. /***************************************************************************/
  175. /*****************************************************************************/
  176. gboolean gn_get_arg_pid(ei_x_buff *xbuf, char *B, int *I, erlang_pid *pid){
  177. if ( ! ei_decode_pid(B ,I, pid) ) return TRUE;
  178. gn_enc_1_error(xbuf, "bad_pid");
  179. return FALSE;
  180. }
  181. gboolean gn_get_arg_gboolean(ei_x_buff *xbuf, char *B, int *I, gboolean *a) {
  182. if ( ! ei_decode_boolean(B, I, a) ) return TRUE;
  183. gn_enc_1_error(xbuf, "bad_boolean");
  184. return FALSE;
  185. }
  186. gboolean gn_get_arg_gchar_fix(ei_x_buff *xbuf, char *B, int *I, char *a){
  187. if ( ! ei_decode_atom(B, I, a) ) return TRUE;
  188. gn_enc_1_error(xbuf, "bad_atom");
  189. return FALSE;
  190. }
  191. /* if gn_get_arg_(g)char returns TRUE, *a must be freed */
  192. gboolean gn_get_arg_char(ei_x_buff *xbuf, char *B, int *I, char **a){
  193. gn_get_arg_gchar(xbuf,B,I,a);
  194. }
  195. gboolean gn_get_arg_gchar(ei_x_buff *xbuf, char *B, int *I, gchar **a) {
  196. int type, size, dummy;
  197. if ( ei_get_type(B, I, &type, &size) ) {
  198. gn_enc_1_error(xbuf, "bad_type");
  199. return FALSE;
  200. }
  201. *a = (gchar *)malloc(size+1);
  202. if ( ! ei_decode_string(B, I, *a) ) return TRUE;
  203. free(*a);
  204. gn_enc_1_error(xbuf, "bad_string");
  205. return FALSE;
  206. }
  207. gboolean gn_get_arg_int(ei_x_buff *xbuf, char *B, int *I, int *a) {
  208. gint64 ll;
  209. if ( ! gn_get_arg_gint64(xbuf, B, I, &ll) ) return FALSE;
  210. *a = ll;
  211. return TRUE;
  212. }
  213. gboolean gn_get_arg_gint(ei_x_buff *xbuf, char *B, int *I, gint *a) {
  214. gint64 ll;
  215. if ( ! gn_get_arg_gint64(xbuf, B, I, &ll) ) return FALSE;
  216. *a = ll;
  217. return TRUE;
  218. }
  219. gboolean gn_get_arg_glong(ei_x_buff *xbuf, char *B, int *I, glong *a) {
  220. gint64 ll;
  221. if ( ! gn_get_arg_gint64(xbuf, B, I, &ll) ) return FALSE;
  222. *a = ll;
  223. return TRUE;
  224. }
  225. gboolean gn_get_arg_gint64(ei_x_buff *xbuf, char *B, int *I, gint64 *a) {
  226. long long ll;
  227. if ( ! ei_decode_longlong(B ,I, &ll) ) {
  228. *a = ll;
  229. return TRUE;
  230. }
  231. gn_enc_1_error(xbuf, "bad_longlong");
  232. return FALSE;
  233. }
  234. gboolean gn_get_arg_guint16(ei_x_buff *xbuf, char *B, int *I, guint16 *a) {
  235. guint gui;
  236. if ( ! gn_get_arg_guint(xbuf,B,I,&gui) ) return FALSE;
  237. *a = gui;
  238. return TRUE;
  239. }
  240. gboolean gn_get_arg_guint32(ei_x_buff *xbuf, char *B, int *I, guint32 *a) {
  241. guint gui;
  242. if ( ! gn_get_arg_guint(xbuf,B,I,&gui) ) return FALSE;
  243. *a = gui;
  244. return TRUE;
  245. }
  246. gboolean gn_get_arg_guint(ei_x_buff *xbuf, char *B, int *I, guint *a) {
  247. unsigned long long ull;
  248. if ( ! ei_decode_ulonglong(B, I, &ull) ) {
  249. *a = ull;
  250. return TRUE;
  251. }
  252. gn_enc_1_error(xbuf, "bad_uint");
  253. return FALSE;
  254. }
  255. gboolean gn_get_arg_gfloat(ei_x_buff *xbuf, char *B, int *I, gfloat *a) {
  256. gdouble dbl;
  257. if ( ! gn_get_arg_gdouble(xbuf, B, I, &dbl) ) return FALSE;
  258. *a = dbl;
  259. return TRUE;
  260. }
  261. gboolean gn_get_arg_gdouble(ei_x_buff *xbuf, char *B, int *I, gdouble *a) {
  262. if ( ! ei_decode_double(B, I, a) ) return TRUE;
  263. gn_enc_1_error(xbuf, "bad_double");
  264. return FALSE;
  265. }
  266. gboolean gn_get_arg_enum(ei_x_buff *xbuf, char *B, int *I, gchar* ec, gint *i) {
  267. gchar enum_name[MAXATOMLEN+1];
  268. if ( ! gn_get_arg_gchar_fix(xbuf, B, I, enum_name) ) return FALSE;
  269. if ( ! gn_get_enum_val(xbuf, ec, enum_name, i) ) return FALSE;
  270. return TRUE;
  271. }
  272. gboolean gn_get_arg_flags(ei_x_buff *xbuf, char *B, int *I,
  273. gchar* type_name, gint *flags) {
  274. GType gtyp;
  275. GFlagsClass* fclass;
  276. GFlagsValue* fval;
  277. char flag_name[MAXATOMLEN+1];
  278. int list_len;
  279. *flags = 0;
  280. if ( (list_len = gn_get_list(xbuf,B,I)) < 0 ) return FALSE;
  281. if ( ! (gtyp = gn_GType_from_name(type_name))) {
  282. gn_enc_2_error(xbuf, "bad_flag_type");
  283. ei_x_encode_atom(xbuf, type_name);
  284. return FALSE;
  285. }
  286. if ( ! G_TYPE_IS_FLAGS(gtyp)) {
  287. gn_enc_2_error(xbuf, "bad_type_flag");
  288. ei_x_encode_atom(xbuf, type_name);
  289. return FALSE;
  290. }
  291. fclass = g_type_class_ref(gtyp);
  292. while ( list_len-- ) {
  293. if ( ei_decode_atom(B, I, flag_name) ) {
  294. gn_enc_2_error(xbuf, "bad_flag_atom");
  295. ei_x_encode_atom(xbuf, type_name);
  296. g_type_class_unref(fclass);
  297. return FALSE;
  298. }
  299. fval = g_flags_get_value_by_name(fclass, flag_name);
  300. *flags = *flags | fval->value;
  301. }
  302. g_type_class_unref(fclass);
  303. return TRUE;
  304. }
  305. /* if get_arg_list returns TRUE, *list must be freed */
  306. gboolean gn_get_arg_list(ei_x_buff *xbuf, char *B, int *I,
  307. gchar* type_name, void** list) {
  308. GType gtyp;
  309. GType* tlist;
  310. char tname[MAXATOMLEN+1];
  311. int list_len, i;
  312. if ( strcmp(type_name,"GType") != 0 ) { /* only GType* yet */
  313. gn_enc_1_error(xbuf, "bad_list_type");
  314. return FALSE;
  315. }
  316. if ( (list_len = gn_get_list(xbuf,B,I)) < 0 ) return FALSE;
  317. tlist = g_new(GType, list_len);
  318. for (i = 0; i < list_len; i++) {
  319. if ( ei_decode_atom(B, I, tname) ) {
  320. g_free(tlist);
  321. gn_enc_1_error(xbuf, "bad_type_atom");
  322. return FALSE;
  323. }
  324. if ( ! (gtyp = gn_GType_from_name(tname)) ){
  325. g_free(tlist);
  326. gn_enc_2_error(xbuf, "bad_type");
  327. ei_x_encode_atom(xbuf, tname);
  328. return FALSE;
  329. }
  330. tlist[i] = gtyp;
  331. }
  332. *list = (void*)tlist;
  333. return TRUE;
  334. }
  335. gboolean gn_get_arg_object(ei_x_buff *xbuf, char *B, int *I,
  336. GType type, GObject** go) {
  337. char object_name[MAXATOMLEN+1];
  338. if ( ei_decode_atom(B, I, object_name) ) {
  339. gn_enc_1_error(xbuf, "bad_object_atom");
  340. return FALSE;
  341. }
  342. if ( strcmp(object_name,"NULL") == 0 ) {
  343. *go = NULL;
  344. }else if ( ! gn_check_object(xbuf, object_name, type, go) ) {
  345. return FALSE;
  346. }
  347. return TRUE;
  348. }
  349. gboolean gn_get_arg_struct(ei_x_buff *xbuf, char *B, int *I,
  350. char* type, void** pp) {
  351. char str_name[MAXATOMLEN+1];
  352. if ( ei_decode_atom(B, I, str_name) ) {
  353. gn_enc_1_error(xbuf, "bad_struct_atom");
  354. return FALSE;
  355. }
  356. if ( strcmp(str_name,"NULL") == 0 ) {
  357. *pp = NULL;
  358. }else if ( ! gn_check_struct(xbuf, str_name, type, pp) ) {
  359. return FALSE;
  360. }
  361. return TRUE;
  362. }
  363. /***************************************************************************/
  364. /* there is a problem in sending references to objects to the erlang node.
  365. * the erlang node can have stale references, (freed pointers). if the
  366. * erlang node sends such to the cnode it will likely crash.
  367. * the cnode needs a way to check that the references from the erlang side
  368. * are still alive. possibly by storing a reference-object pointer tuple in
  369. * a table (on the cnode)? tuples must be removed when object is destroyed,
  370. * so the table must be indexed both ways. connect a destroy signal to each
  371. * object? use glib's hash? use erlang references?
  372. */
  373. gboolean gn_check_object(ei_x_buff *xbuf, gchar* object_name,
  374. GType type, GObject** object) {
  375. void* vp;
  376. GType GT;
  377. if ( (vp = hash_lookup(object_name)) ) {
  378. /* dynamic object */
  379. }else if ( (vp = gn_check_widget_name(object_name))) {
  380. /* named widget */
  381. }else{
  382. gn_enc_2_error(xbuf, "bad_object");
  383. ei_x_encode_atom(xbuf, object_name);
  384. return FALSE;
  385. }
  386. *object = G_OBJECT(vp);
  387. if ( G_TYPE_CHECK_INSTANCE_TYPE ((*object), type) ) return TRUE;
  388. GT = G_TYPE_FROM_INSTANCE(*object);
  389. gn_enc_2_error(xbuf, "bad_type");
  390. ei_x_encode_atom(xbuf, g_type_name(GT));
  391. return FALSE;
  392. }
  393. gboolean gn_check_struct(ei_x_buff *xbuf,
  394. char* struct_name, char* struct_type,void** pp) {
  395. extern GModule *gmod;
  396. gchar con_str[200] = "gn_construct_";
  397. gchar key[200];
  398. void* (*constr)(void);
  399. memcpy(key,struct_type,strlen(struct_type)+1);
  400. strcat(key,"-");
  401. strcat(key,struct_name);
  402. if ( (*pp = hash_lookup(key)) ) {
  403. return TRUE;
  404. }else{
  405. strcat(con_str,struct_type);
  406. g_module_symbol(gmod, con_str, (gpointer *)&constr);
  407. if ( ! constr ) {
  408. gn_enc_2_error(xbuf, "bad_constructor");
  409. ei_x_encode_atom(xbuf, con_str);
  410. return FALSE;
  411. }
  412. *pp = (*constr)();
  413. hash_insert(key,*pp);
  414. return TRUE;
  415. }
  416. }
  417. gboolean gn_check_arity(ei_x_buff *xbuf, int a1, int a2) {
  418. if ( a1 == a2 ) return TRUE;
  419. gn_enc_2_error(xbuf, "bad_arity");
  420. ei_x_encode_long(xbuf, (long) a2);
  421. return FALSE;
  422. }
  423. /***************************************************************************/
  424. gint gn_get_list(ei_x_buff *xbuf, char *B, int *I) {
  425. int ari;
  426. if ( ! ei_decode_list_header(B, I, &ari) ) return ari;
  427. gn_enc_1_error(xbuf, "bad_list");
  428. return -1;
  429. }
  430. gint gn_get_tuple(ei_x_buff *xbuf, char *B, int *I) {
  431. int ari;
  432. if ( ! ei_decode_tuple_header(B, I, &ari) ) return ari;
  433. gn_enc_1_error(xbuf, "bad_tuple");
  434. return -1;
  435. }
  436. /***************************************************************************/
  437. static GEnumClass* get_enum_class(const gchar *type_name) {
  438. GType gtyp;
  439. if ( ! (gtyp = gn_GType_from_name(type_name)))
  440. return NULL;
  441. if ( ! G_TYPE_IS_ENUM(gtyp))
  442. return NULL;
  443. return g_type_class_ref(gtyp);
  444. }
  445. gboolean gn_get_enum_val(ei_x_buff *xbuf,
  446. const gchar *type_name, gchar *enum_name, gint *i) {
  447. GEnumClass* eclass;
  448. GEnumValue* eval;
  449. if ( ! (eclass = get_enum_class(type_name)) ) {
  450. gn_enc_2_error(xbuf, "bad_enum_type");
  451. ei_x_encode_atom(xbuf, type_name);
  452. return FALSE;
  453. }
  454. eval = g_enum_get_value_by_name(eclass, enum_name);
  455. g_type_class_unref(eclass);
  456. if ( ! eval ) {
  457. gn_enc_2_error(xbuf, "bad_enum_name");
  458. ei_x_encode_atom(xbuf, enum_name);
  459. return FALSE;
  460. }
  461. *i = eval->value;
  462. return TRUE;
  463. }
  464. gboolean gn_get_enum_name(const gchar *type_name, gint i, gchar *enum_name) {
  465. GEnumClass* eclass;
  466. GEnumValue *eval;
  467. if ( ! (eclass = get_enum_class(type_name)) )
  468. return FALSE;
  469. eval = g_enum_get_value(eclass, i);
  470. g_type_class_unref(eclass);
  471. if ( ! eval )
  472. return FALSE;
  473. memcpy(enum_name, eval->value_name, strlen(eval->value_name)+1);
  474. return TRUE;
  475. }
  476. /***************************************************************************/
  477. /* {{Pid,signal},{Widget,EvType}} */
  478. /***************************************************************************/
  479. void gn_send_signal(const char *widgetname, char *evtyp) {
  480. ei_x_buff xbuf;
  481. ei_x_new_with_version(&xbuf);
  482. gn_wrap_ans("signal", &xbuf);
  483. ei_x_encode_tuple_header(&xbuf,2);
  484. ei_x_encode_atom(&xbuf, widgetname);
  485. ei_x_encode_atom(&xbuf, evtyp);
  486. gn_send(&xbuf);
  487. ei_x_free(&xbuf);
  488. }
  489. /***************************************************************************/