mirror of https://github.com/GNOME/gimp.git
333 lines
7.3 KiB
C
333 lines
7.3 KiB
C
#include "gcg.h"
|
|
#include "output.h"
|
|
#include "marshall.h"
|
|
|
|
|
|
static GHashTable* sigtype_hash;
|
|
|
|
typedef enum {
|
|
MARSHALL_INT,
|
|
MARSHALL_DOUBLE,
|
|
MARSHALL_POINTER,
|
|
MARSHALL_VOID,
|
|
MARSHALL_LONG
|
|
} MarshallType;
|
|
|
|
|
|
struct _SignalType {
|
|
Id package;
|
|
Id module;
|
|
MarshallType rettype;
|
|
GSList* argtypes;
|
|
};
|
|
|
|
MarshallType marshalling_type(Type* t){
|
|
if(!t)
|
|
return MARSHALL_VOID;
|
|
if(t->indirection)
|
|
return MARSHALL_POINTER;
|
|
if(!t->prim)
|
|
return MARSHALL_VOID;
|
|
switch(t->prim->kind){
|
|
case TYPE_INT:
|
|
case TYPE_FLAGS:
|
|
case TYPE_ENUM:
|
|
return MARSHALL_INT;
|
|
case TYPE_LONG:
|
|
return MARSHALL_LONG;
|
|
case TYPE_DOUBLE:
|
|
return MARSHALL_DOUBLE;
|
|
case TYPE_NONE:
|
|
return MARSHALL_VOID;
|
|
default:
|
|
g_assert_not_reached();
|
|
return MARSHALL_VOID;
|
|
}
|
|
}
|
|
|
|
/* Yes, this is hyperbly kludgetical */
|
|
|
|
SignalType* sig_type(Method* m){
|
|
SignalType *t=g_new(SignalType, 1), *s;
|
|
GSList* p=m->params, *a=NULL;
|
|
PNode* g;
|
|
gchar* f;
|
|
t->package = DEF(MEMBER(m)->my_class)->type->module->package->name;
|
|
t->module = DEF(MEMBER(m)->my_class)->type->module->name;
|
|
t->rettype = marshalling_type(&m->ret_type);
|
|
if(!sigtype_hash)
|
|
sigtype_hash = g_hash_table_new(g_str_hash, g_str_equal);
|
|
while(p){
|
|
Param* param=p->data;
|
|
MarshallType* t=g_new(MarshallType, 1);
|
|
*t=marshalling_type(¶m->type);
|
|
a=g_slist_prepend(a, t);
|
|
p=p->next;
|
|
}
|
|
a=g_slist_reverse(a);
|
|
t->argtypes=a;
|
|
g = p_signal_demarshaller_name(t);
|
|
f = p_to_str(g, NULL);
|
|
p_unref(g);
|
|
s = g_hash_table_lookup(sigtype_hash, f);
|
|
if(!s){
|
|
g_hash_table_insert(sigtype_hash, f, t);
|
|
return t;
|
|
}
|
|
else{
|
|
sig_type_free(t);
|
|
g_free(f);
|
|
return s;
|
|
}
|
|
}
|
|
|
|
void sig_type_free(SignalType* t){
|
|
GSList* l=t->argtypes;
|
|
while(l){
|
|
g_free(l->data);
|
|
l=l->next;
|
|
}
|
|
g_slist_free(t->argtypes);
|
|
g_free(t);
|
|
}
|
|
|
|
typedef enum{
|
|
GTKNAME,
|
|
ENCODING,
|
|
CTYPE
|
|
} MMap;
|
|
|
|
|
|
PNode* p_gtype_name(MarshallType t, MMap map){
|
|
static const struct GTypeName{
|
|
MarshallType type;
|
|
Id gtkname;
|
|
Id encoding;
|
|
Id ctype;
|
|
}names[]={
|
|
{MARSHALL_POINTER, "POINTER", "P", "gpointer"},
|
|
{MARSHALL_INT, "INT", "I", "gint"},
|
|
{MARSHALL_DOUBLE, "DOUBLE", "D", "gdouble"},
|
|
{MARSHALL_LONG, "LONG", "L", "glong"},
|
|
{MARSHALL_VOID, "NONE", "0", "void"},
|
|
};
|
|
gint i;
|
|
|
|
for(i=0;i<(gint)(sizeof(names)/sizeof(names[0]));i++)
|
|
if(names[i].type==t){
|
|
Id id;
|
|
switch(map){
|
|
case GTKNAME:
|
|
id = names[i].gtkname;
|
|
break;
|
|
case ENCODING:
|
|
id = names[i].encoding;
|
|
break;
|
|
case CTYPE:
|
|
id = names[i].ctype;
|
|
break;
|
|
}
|
|
return p_str(id);
|
|
}
|
|
|
|
g_assert_not_reached();
|
|
return NULL;
|
|
}
|
|
|
|
PNode* p_gtabbr(gpointer p){
|
|
MarshallType* t=p;
|
|
return p_gtype_name(*t, ENCODING);
|
|
}
|
|
|
|
|
|
|
|
PNode* p_gtktype(Type* t){
|
|
if(t->indirection==0){
|
|
if(!t->prim)
|
|
return p_str("GTK_TYPE_NONE");
|
|
switch(t->prim->kind){
|
|
case TYPE_INT:
|
|
return p_str("GTK_TYPE_INT");
|
|
case TYPE_DOUBLE:
|
|
return p_str("GTK_TYPE_DOUBLE");
|
|
case TYPE_ENUM:
|
|
case TYPE_FLAGS:
|
|
return p_macro_name(t->prim, "TYPE", NULL);
|
|
case TYPE_CHAR:
|
|
return p_str("GTK_TYPE_CHAR");
|
|
case TYPE_FOREIGN:
|
|
g_error("Cannot marshall foreign type %s.%s!",
|
|
t->prim->module->package->name,
|
|
t->prim->name);
|
|
return NULL;
|
|
default:
|
|
g_error("Cannot marshall type by value: %s.%s",
|
|
t->prim->module->package->name,
|
|
t->prim->name);
|
|
return NULL;
|
|
}
|
|
}else if(t->indirection==1
|
|
&& t->prim
|
|
&& (t->prim->kind==TYPE_BOXED
|
|
|| t->prim->kind==TYPE_OBJECT))
|
|
return p_macro_name(t->prim, "TYPE", NULL);
|
|
else
|
|
return p_str("GTK_TYPE_POINTER");
|
|
}
|
|
|
|
|
|
PNode* p_signal_func_name(SignalType* t, PNode* basename){
|
|
#if 1
|
|
return p_fmt("_~_~_~_~~",
|
|
p_c_ident(t->package),
|
|
p_c_ident(t->module),
|
|
basename,
|
|
p_gtype_name(t->rettype, ENCODING),
|
|
p_for(t->argtypes, p_gtabbr, p_nil));
|
|
#else
|
|
return p_fmt("_~_~_~~",
|
|
p_c_ident(t->package),
|
|
basename,
|
|
p_gtype_name(t->rettype, ENCODING),
|
|
p_for(t->argtypes, p_gtabbr, p_nil));
|
|
#endif
|
|
}
|
|
|
|
PNode* p_signal_marshaller_name(SignalType* t){
|
|
return p_signal_func_name(t, p_str("marshall"));
|
|
}
|
|
|
|
PNode* p_signal_demarshaller_name(SignalType* t){
|
|
return p_signal_func_name(t, p_str("demarshall"));
|
|
}
|
|
|
|
PNode* p_handler_type(SignalType* t){
|
|
#if 1
|
|
return p_fmt("_~~Handler_~~",
|
|
p_str(t->package),
|
|
p_str(t->module),
|
|
p_gtype_name(t->rettype, ENCODING),
|
|
p_for(t->argtypes, p_gtabbr, p_nil));
|
|
#else
|
|
return p_fmt("_~Handler_~~",
|
|
p_str(t->package),
|
|
p_gtype_name(t->rettype, ENCODING),
|
|
p_for(t->argtypes, p_gtabbr, p_nil));
|
|
#endif
|
|
}
|
|
|
|
PNode* p_signal_id(Method* s){
|
|
PrimType* t=DEF(MEMBER(s)->my_class)->type;
|
|
return p_fmt("_~_~_signal_~",
|
|
p_c_ident(t->module->package->name),
|
|
p_c_ident(t->name),
|
|
p_c_ident(MEMBER(s)->name));
|
|
}
|
|
|
|
typedef struct{
|
|
PNode* args;
|
|
gint idx;
|
|
}ArgMarshData;
|
|
|
|
PNode* p_arg_marsh(gpointer p, gpointer d){
|
|
Param* par=p;
|
|
gint* idx=d;
|
|
(*idx)++;
|
|
return p_fmt(/* "\targs[~].type=~;\n" unnecessary... */
|
|
"\tGTK_VALUE_~(args[~]) = ~;\n",
|
|
/* p_prf("%d", *idx),
|
|
p_gtktype(&par->type), */
|
|
p_gtype_name(marshalling_type(&par->type), GTKNAME),
|
|
p_prf("%d", *idx),
|
|
p_c_ident(par->name));
|
|
}
|
|
|
|
PNode* p_sig_marshalling(Method* m){
|
|
gint idx=-1;
|
|
gint nargs = g_slist_length(m->params);
|
|
gboolean ret = marshalling_type(&m->ret_type)!=MARSHALL_VOID;
|
|
return p_fmt("\t{\n"
|
|
"~"
|
|
"~"
|
|
"~"
|
|
"~"
|
|
"\tgtk_signal_emitv((GtkObject*)~, ~, ~);\n"
|
|
"~"
|
|
"\t}\n",
|
|
nargs > 0
|
|
? p_fmt("\tGtkArg args[~];\n",
|
|
p_prf("%d", nargs+ret))
|
|
: p_nil,
|
|
ret
|
|
?p_fmt("\t~ retval;\n",
|
|
p_type(&m->ret_type))
|
|
:p_nil,
|
|
p_for(m->params, p_arg_marsh, &idx),
|
|
ret
|
|
/* cannot use retloc here, ansi forbids casted lvalues */
|
|
?p_fmt("\tGTK_VALUE_POINTER(args[~]) = &retval;\n",
|
|
p_prf("%d", nargs))
|
|
:p_nil,
|
|
p_c_ident(DEF(MEMBER(m)->my_class)->type->name),
|
|
p_signal_id(m),
|
|
nargs > 0
|
|
? p_str("args")
|
|
: p_str("NULL"),
|
|
ret
|
|
?p_str("\treturn retval;\n")
|
|
:p_nil);
|
|
}
|
|
|
|
|
|
PNode* p_arg_demarsh(gpointer p, gpointer d){
|
|
MarshallType* t=p;
|
|
gint* data=d;
|
|
(*data)++;
|
|
return p_fmt("\t\tGTK_VALUE_~(args[~]),\n",
|
|
p_gtype_name(*t, FALSE),
|
|
p_prf("%d", *data));
|
|
}
|
|
|
|
PNode* p_sig_arg_ctype(MarshallType* t){
|
|
return p_fmt(", ~", p_gtype_name(*t, CTYPE));
|
|
}
|
|
|
|
PNode* p_sigdemarsh_decl(SignalType* t){
|
|
#if 1
|
|
return p_fmt("static void ~ (GtkObject*, GtkSignalFunc, "
|
|
"gpointer, GtkArg*);\n"
|
|
"typedef ~ (*~)(GtkObject*~, gpointer);\n",
|
|
p_signal_demarshaller_name(t),
|
|
p_gtype_name(t->rettype, CTYPE),
|
|
p_handler_type(t),
|
|
p_for(t->argtypes, p_sig_arg_ctype, p_nil));
|
|
#else
|
|
return p_fmt("extern void ~ (GtkObject*, GtkSignalFunc, "
|
|
"gpointer, GtkArg*);\n",
|
|
p_signal_demarshaller_name(t));
|
|
#endif
|
|
}
|
|
|
|
PNode* p_demarshaller(SignalType* t){
|
|
gint idx=-1;
|
|
return p_fmt("static void ~ (\n"
|
|
"\tGtkObject* object,\n"
|
|
"\tGtkSignalFunc func,\n"
|
|
"\tgpointer user_data,\n"
|
|
"\tGtkArg* args){\n"
|
|
"\t(void)args;\n"
|
|
"~~"
|
|
"}\n",
|
|
p_signal_demarshaller_name(t),
|
|
(t->rettype==TYPE_NONE)
|
|
? p_fmt("\t*(GTK_RETLOC_~(args[~])) =\n",
|
|
p_gtype_name(t->rettype, FALSE),
|
|
p_prf("%d", g_slist_length(t->argtypes)))
|
|
: p_nil,
|
|
p_fmt("\t~(object,\n"
|
|
"~"
|
|
"\tuser_data);\n",
|
|
p_cast(p_handler_type(t), p_str("func")),
|
|
p_for(t->argtypes, p_arg_demarsh, &idx)));
|
|
}
|