/*************************************************************************** CApplication.cpp The KDE DCOP Application class (c) 2000-2007 Benoit Minisini This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ***************************************************************************/ #define __CAPPLICATION_CPP #include #include #include #include #include #include #include #include #include #include "gambas.h" #include "main.h" #include "../share/CPicture.h" #include "../share/CImage.h" #include "../share/CMouse.h" #include "../share/CFont.h" #include "CApplication.h" //#define DEBUG_ME typedef struct { const char *dcop; GB_TYPE type; } TYPE_CONV; enum { QT_T_VOID, QT_T_ASYNC, QT_T_BOOL, QT_T_INT, QT_T_UNSIGNED, QT_T_UINT, QT_T_LONG, QT_T_ULONG, QT_T_QCOLOR, QT_T_FLOAT, QT_T_DOUBLE, QT_T_QCSTRING, QT_T_QSTRING, QT_T_KURL, QT_T_KURL_LIST, QT_T_QVARIANT, QT_T_QCSTRINGLIST, QT_T_QSTRINGLIST, QT_T_QMAP_QCSTRING_QSTRING, QT_T_QMAP_QSTRING_QSTRING, QT_T_DCOPREF, QT_T_QVALUELIST_DCOPREF, QT_T_QMAP_QCSTRING_DCOPREF, QT_T_QMAP_QSTRING_DCOPREF, QT_T_QPIXMAP, QT_T_QIMAGE, QT_T_QCURSOR, QT_T_QPOINT, QT_T_QSIZE, QT_T_QRECT, QT_T_QFONT, }; static TYPE_CONV type_conv[] = { { "void", GB_T_VOID }, { "ASYNC", GB_T_VOID }, { "bool", GB_T_BOOLEAN }, { "int", GB_T_INTEGER }, { "unsigned", GB_T_INTEGER }, { "uint", GB_T_INTEGER }, { "long", GB_T_INTEGER }, { "ulong", GB_T_INTEGER }, { "QColor", GB_T_INTEGER }, { "float", GB_T_FLOAT }, { "double", GB_T_FLOAT }, { "QCString", GB_T_STRING }, { "QString", GB_T_STRING }, { "KURL", GB_T_STRING }, { "KURL::List", (GB_TYPE)"String[]" }, { "QVariant", GB_T_VARIANT }, { "QCStringList", (GB_TYPE)"String[]" }, { "QStringList", (GB_TYPE)"String[]" }, { "QMap", (GB_TYPE)"Collection" }, { "QMap", (GB_TYPE)"Collection" }, { "DCOPRef", (GB_TYPE)"DCOPRef" }, { "QValueList", (GB_TYPE)"Object[]" }, { "QMap", (GB_TYPE)"Collection" }, { "QMap", (GB_TYPE)"Collection" }, { "QPixmap", (GB_TYPE)"Picture" }, { "QImage", (GB_TYPE)"Image" }, { "QCursor", (GB_TYPE)"Cursor" }, { "QPoint", (GB_TYPE)"Integer[]" }, { "QSize", (GB_TYPE)"Integer[]" }, { "QRect", (GB_TYPE)"Integer[]" }, { "QFont", (GB_TYPE)"Font" }, { NULL } }; static QAsciiDict< CAPPLICATION > appCache; static int get_type(const char *type) { TYPE_CONV *p; int i; #ifdef DEBUG_ME qDebug("get_type(%s)", type); #endif if (type == 0 || *type == 0) return 0; for (p = type_conv, i = 0; p->dcop; p++, i++) if (strcasecmp(p->dcop, type) == 0) { #ifdef DEBUG_ME qDebug("-> %d", i); #endif return i; } return (-1); } static void flush_application() { QAsciiDictIterator it(appCache); CAPPLICATION *app; //qDebug("flush_application"); while (it.current()) { //delete it.current()->pixmap; app = it.current(); GB.Unref(POINTER(&app)); ++it; } } static CAPPLICATION *get_application(const char *name, bool exec = true) { QCString app; CAPPLICATION *_object = 0; bool reg; DCOPClient *dcop = kapp->dcopClient(); app = name; reg = dcop->isApplicationRegistered(app); if (!reg) { QCStringList apps = dcop->registeredApplications(); QCString appId = dcop->appId(); for (QCStringList::ConstIterator it = apps.begin(); it != apps.end(); ++it) { if ((*it) != appId && (*it).left(9) != "anonymous") { if ((*it).find(app) == 0) { app = *it; reg = true; break; } } } } #ifdef DEBUG_ME if (reg) qDebug("Application is already registered"); #endif if (!reg) { QString sName(name); QString url; QString error; int i; i = sName.find(' '); if (i >= 0) { url = sName.mid(i + 1).stripWhiteSpace(); sName = sName.left(i).stripWhiteSpace(); } if (exec) { #ifdef DEBUG_ME qDebug("starting %s...", sName.latin1()); #endif kapp->startServiceByDesktopName(sName, url, &error); } if (error.length()) { GB.Error("Cannot start KDE application: &1", error.latin1()); return NULL; } else return get_application(name, false); } if (!appCache.isEmpty()) _object = appCache[app]; if (!_object) { GB.New(POINTER(&_object), GB.FindClass("KDEApplication"), NULL, NULL); GB.Ref(THIS); GB.NewString(&THIS->name, app, app.length()); THIS->object = NULL; THIS->cache = new QAsciiDict< QDict >(17, false); THIS->cache->setAutoDelete(true); appCache.insert(app, THIS); } return THIS; } static CDCOPREF *make_dcopref(DCOPRef& dcopref) { CDCOPREF *_object; if (dcopref.isNull()) return NULL; GB.New(POINTER(&_object), GB.FindClass("DCOPRef"), NULL, NULL); _object->ref = new DCOPRef(dcopref); //qDebug("Create DCOPREF %p", _object); return _object; } BEGIN_METHOD_VOID(CAPPLICATION_exit) flush_application(); END_METHOD BEGIN_METHOD_VOID(CAPPLICATION_free) GB.FreeString(&THIS->name); GB.FreeString(&THIS->object); delete THIS->cache; THIS->cache = 0; END_METHOD BEGIN_PROPERTY(CAPPLICATION_name) GB.ReturnString(THIS->name); END_PROPERTY BEGIN_METHOD(CAPPLICATION_get, GB_STRING name) GB.ReturnObject(get_application(GB.ToZeroString(ARG(name)))); END_METHOD static void get_object(CAPPLICATION *_object, const char *name) { GB.FreeString(&THIS->object); GB.NewString(&THIS->object, name, 0); GB.ReturnObject(THIS); } BEGIN_METHOD(CAPPLICATION_get_object, GB_STRING object) get_object(THIS, GB.ToZeroString(ARG(object))); END_METHOD static CFunction *get_function(CAPPLICATION *_object, const char *iname, const char *name, int nparam) { QDict *iface = 0; CFunction *func = NULL; if (!iname) iname = "default"; if (!THIS->cache->isEmpty()) iface = (*THIS->cache)[iname]; if (iface == 0) { bool ok; QCStringList funcs; QString dcsign, dctype, dcname; QStringList dcargs; int l, r, i; iface = new QDict(17, false); iface->setAutoDelete(true); #ifdef DEBUG_ME qDebug("**** %s.%s", THIS->name, iname); #endif funcs = kapp->dcopClient()->remoteFunctions(THIS->name, iname, &ok); if (!ok) return NULL; for (QCStringList::ConstIterator it = funcs.begin(); it != funcs.end(); ++it) { //dcsign = kapp->dcopClient()->normalizeFunctionSignature(*it); dcsign = *it; /* Type DCOP de retour */ i = dcsign.find(" "); if (i >= 0) dctype = dcsign.left(i); dcsign = dcsign.mid(i + 1); l = dcsign.find('('); r = dcsign.findRev(')'); if (l < 0 || r < 0) continue; /* Nom DCOP de la m�hode */ dcname = dcsign.left(l).stripWhiteSpace(); dcsign = dcsign.mid(l + 1, r - l - 1); /* Types des arguments de la m�hode */ dcargs = QStringList::split(',', dcsign); for (QStringList::Iterator it = dcargs.begin(); it != dcargs.end(); ++it) { (*it) = (*it).stripWhiteSpace(); i = (*it).find(' '); if (i >= 0) (*it) = (*it).left(i); } func = new CFunction(); func->dcopName = dcname + "(" + dcargs.join(",") + ")"; #ifdef DEBUG_ME qDebug("dcopName = %s", (const char *)func->dcopName); #endif /* Nom Gambas de la m�hode */ dcname += QString::number(dcargs.count()); QString dcname2 = dcname; for(i = 1; i < 256; i++) { dcname2 = dcname; if (i > 1) dcname2 += QString::number(i); if (iface->isEmpty() || iface->find(dcname2) == 0) { func->name = dcname2; break; } } #ifdef DEBUG_ME qDebug("name = %s", (const char *)func->name); #endif func->type = get_type(dctype.latin1()); #ifdef DEBUG_ME qDebug("type = %s", (const char *)dctype); #endif func->args = new int[dcargs.count()]; #ifdef DEBUG_ME for (QStringList::Iterator it = dcargs.begin(); it != dcargs.end(); ++it) qDebug("arg = %s", (*it).latin1()); qDebug(" "); #endif i = 0; for (QStringList::Iterator it = dcargs.begin(); it != dcargs.end(); ++it, ++i) func->args[i] = get_type((*it).latin1()); iface->insert((const char *)func->name, func); } THIS->cache->insert(iname, iface); } if (!iface->isEmpty()) func = (*iface)[QString(name) + QString::number(nparam)]; return func; } #define GET_STRING(_arg) (TO_QSTRING(GB.ToZeroString((GB_STRING *)_arg))) #define GET_OBJECT(_arg, _type) ((_type *)(((GB_OBJECT *)_arg)->value)) static bool call_method(CAPPLICATION *_object, const char *object, const char *name, GB_VALUE *args, int nparam, bool error) { int i, n, ret, j; GB_VALUE *arg; bool ok; int type; GB_TYPE gtype; QByteArray data, replyData; CFunction *func; void *ob = NULL; n = nparam; func = get_function(THIS, object, name, n); if (!func) { if (error) { if (object) GB.Error("Unknown method: &1.&2.&3", THIS->name, object, name); else GB.Error("Unknown method: &1.&2", THIS->name, name); } return true; } #ifdef DEBUG_ME qDebug("call_method: %s.%s.%s", THIS->name, object, name); #endif /* Conversion & Marshalling */ QDataStream d(data, IO_WriteOnly); for (i = 0; i < n; i++) { arg = &args[i]; type = func->args[i]; if (type < 0) { GB.Error("Cannot handle datatype"); return true; } gtype = type_conv[type].type; if (gtype < GB_T_OBJECT) ret = GB.Conv(arg, gtype); else { ret = GB.Conv(arg, (GB_TYPE)GB.FindClass((const char *)gtype)); if (!ret) { ob = GET_OBJECT(arg, void); ret = GB.CheckObject(ob); } } if (ret) return true; if (type == QT_T_INT) d << (int)((GB_INTEGER *)arg)->value; else if (type == QT_T_UNSIGNED || type == QT_T_UINT) d << (unsigned int)((GB_INTEGER *)arg)->value; else if (type == QT_T_LONG) d << (long)((GB_INTEGER *)arg)->value; else if (type == QT_T_ULONG) d << (unsigned long)((GB_INTEGER *)arg)->value; else if (type == QT_T_FLOAT) d << (float)((GB_FLOAT *)arg)->value; else if (type == QT_T_DOUBLE) d << (double)((GB_FLOAT *)arg)->value; else if (type == QT_T_BOOL) d << (bool)((GB_BOOLEAN *)arg)->value; else if (type == QT_T_QCSTRING) d << QCString(GET_STRING(arg)); else if (type == QT_T_QSTRING) d << GET_STRING(arg); else if (type == QT_T_QCSTRINGLIST) { GB_ARRAY a = (GB_ARRAY)ob; QCStringList list; char *val; for (j = 0; j < GB.Array.Count(a); j++) { val = *((char **)GB.Array.Get(a, j)); list.append(QCString(TO_QSTRING(val))); } d << list; } else if (type == QT_T_QSTRINGLIST) { GB_ARRAY a = (GB_ARRAY)ob; QStringList list; char *val; for (j = 0; j < GB.Array.Count(a); j++) { val = *((char **)GB.Array.Get(a, j)); list.append(TO_QSTRING(val)); } d << list; } else if (type == QT_T_KURL) d << KURL(GET_STRING(arg)); else if (type == QT_T_KURL_LIST) { GB_ARRAY a = (GB_ARRAY)ob; KURL::List list; char *url; for (j = 0; j < GB.Array.Count(a); j++) { url = *((char **)GB.Array.Get(a, j)); list.append(KURL(TO_QSTRING(url))); } d << list; } else if (type == QT_T_QPIXMAP) d << *(GET_OBJECT(arg, CPICTURE)->pixmap); else if (type == QT_T_QIMAGE) d << *(GET_OBJECT(arg, CIMAGE)->image); else if (type == QT_T_QCURSOR) d << *(GET_OBJECT(arg, CCURSOR)->cursor); else if (type == QT_T_QPOINT) { GB_ARRAY a = (GB_ARRAY)ob; if (GB.Array.Count(a) != 2) { GB.Error("Cannot convert datatype"); return true; } QPoint p(*((int *)GB.Array.Get(a, 0)), *((int *)GB.Array.Get(a, 1))); d << p; } else if (type == QT_T_QSIZE) { GB_ARRAY a = (GB_ARRAY)ob; if (GB.Array.Count(a) != 2) { GB.Error("Cannot convert datatype"); return true; } QSize s(*((int *)GB.Array.Get(a, 0)), *((int *)GB.Array.Get(a, 1))); d << s; } else if (type == QT_T_QRECT) { GB_ARRAY a = (GB_ARRAY)ob; if (GB.Array.Count(a) != 4) { GB.Error("Cannot convert datatype"); return true; } QRect r(*((int *)GB.Array.Get(a, 0)), *((int *)GB.Array.Get(a, 1)), *((int *)GB.Array.Get(a, 2)), *((int *)GB.Array.Get(a, 3))); d << r; } else if (type == QT_T_QFONT) { d << *(GET_OBJECT(arg, CFONT)->font); } else { GB.Error("Cannot handle datatype"); return true; } } QCString cname(THIS->name); QCString cobject(object); QCString ctype; ok = kapp->dcopClient()->call ( cname, cobject, func->dcopName, data, ctype, replyData ); if (!ok) { if (kapp->dcopClient()->isApplicationRegistered(THIS->name)) GB.Error("DCOP call failed"); else GB.Error("Application is not registered anymore"); return true; } /* Demarshalling */ type = get_type(ctype); if (type == QT_T_VOID || type == QT_T_ASYNC) return false; QDataStream reply(replyData, IO_ReadOnly); if (type == QT_T_QVARIANT) { Q_INT32 vt; QString vtn; reply >> vt; vtn = QVariant::typeToName((QVariant::Type)vt); type = get_type(vtn.latin1()); } if (type == QT_T_INT) { int i; reply >> i; GB.ReturnInteger(i); } else if (type == QT_T_UINT) { uint i; reply >> i; GB.ReturnInteger(i); } else if (type == QT_T_LONG) { long l; reply >> l; GB.ReturnInteger(l); } else if (type == QT_T_ULONG) { ulong l; reply >> l; GB.ReturnInteger((long)l); } else if (type == QT_T_FLOAT) { float f; reply >> f; GB.ReturnFloat(f); } else if (type == QT_T_DOUBLE) { double d; reply >> d; GB.ReturnFloat(d); } else if (type == QT_T_BOOL) { bool b; reply >> b; GB.ReturnBoolean(b ? 1 : 0); } else if (type == QT_T_QSTRING) { QString s; reply >> s; GB.ReturnNewZeroString(s); } else if (type == QT_T_QCSTRING) { QCString r; reply >> r; GB.ReturnNewZeroString(r); } else if (type == QT_T_KURL) { KURL r; reply >> r; GB.ReturnNewZeroString(r.prettyURL()); } else if (type == QT_T_QCOLOR) { QColor r; reply >> r; GB.ReturnInteger(r.rgb() & 0xFFFFFF); } else if (type == QT_T_QSTRINGLIST) { GB_ARRAY array; const char *data; QStringList r; reply >> r; n = r.count(); GB.Array.New(&array, GB_T_STRING, n); for (i = 0; i < n; i++) { data = TO_UTF8(r[i]); GB.NewString((char **)GB.Array.Get(array, i), data, 0); } GB.ReturnObject(array); } else if (type == QT_T_QCSTRINGLIST) { GB_ARRAY array; QCStringList r; reply >> r; n = r.count(); GB.Array.New(&array, GB_T_STRING, n); for (i = 0; i < n; i++) GB.NewString((char **)GB.Array.Get(array, i), (const char *)r[i], 0); GB.ReturnObject(array); } else if (type == QT_T_QMAP_QCSTRING_QSTRING) { GB_COLLECTION col; GB_VARIANT value; const char *key; char *data; QMap r; reply >> r; GB.Collection.New(&col, GB_COMP_BINARY); QMap::Iterator it; for (it = r.begin(); it != r.end(); it++) { GB.NewString(&data, TO_UTF8(it.data()), 0); key = (const char *)it.key(); value.type = GB_T_VARIANT; value.value.type = GB_T_STRING; value.value._string.value = (char *)data; GB.Collection.Set(col, key, 0, &value); GB.FreeString(&data); } GB.ReturnObject(col); } else if (type == QT_T_QMAP_QSTRING_QSTRING) { GB_COLLECTION col; GB_VARIANT value; QCString ckey; const char *key; char *data; QMap r; reply >> r; GB.Collection.New(&col, GB_COMP_BINARY); QMap::Iterator it; for (it = r.begin(); it != r.end(); it++) { //ckey = it.data().utf8(); //key = TO_UTF8(it.data()); //GB.NewString(&data, (const char *)ckey, 0); //ckey = it.key().utf8(); key = TO_UTF8(it.key()); GB.NewString(&data, TO_UTF8(it.data()), 0); value.type = GB_T_VARIANT; value.value.type = GB_T_STRING; value.value._string.value = data; GB.Collection.Set(col, key, 0, &value); GB.FreeString(&data); } GB.ReturnObject(col); } else if (type == QT_T_DCOPREF) { DCOPRef r; reply >> r; GB.ReturnObject(make_dcopref(r)); } else if (type == QT_T_QVALUELIST_DCOPREF) { GB_ARRAY array; QValueList r; reply >> r; CDCOPREF *ref; n = r.count(); GB.Array.New(&array, GB_T_OBJECT, n); for (i = 0; i < n; i++) { ref = make_dcopref(r[i]); GB.Ref(ref); *((CDCOPREF **)GB.Array.Get(array, i)) = ref; } GB.ReturnObject(array); } else if (type == QT_T_QMAP_QSTRING_DCOPREF) { GB_COLLECTION col; GB_VARIANT value; const char *key; CDCOPREF *ref; QMap r; reply >> r; GB.Collection.New(&col, GB_COMP_BINARY); QMap::Iterator it; for (it = r.begin(); it != r.end(); it++) { key = TO_UTF8(it.key()); value.type = GB_T_VARIANT; value.value.type = GB_T_OBJECT; ref = make_dcopref(it.data()); //GB.Ref(ref); value.value._object.value = ref; GB.Collection.Set(col, key, 0, &value); } GB.ReturnObject(col); } else if (type == QT_T_QMAP_QCSTRING_DCOPREF) { GB_COLLECTION col; GB_VARIANT value; const char *key; CDCOPREF *ref; QMap r; reply >> r; GB.Collection.New(&col, GB_COMP_BINARY); QMap::Iterator it; for (it = r.begin(); it != r.end(); it++) { key = (const char *)it.key(); value.type = GB_T_VARIANT; value.value.type = GB_T_OBJECT; ref = make_dcopref(it.data()); //GB.Ref(ref); value.value._object.value = ref; //qDebug("key: %s ref: %p", key, ref); GB.Collection.Set(col, key, 0, &value); } GB.ReturnObject(col); } else if (type == QT_T_QPOINT) { GB_ARRAY array; QPoint r; reply >> r; GB.Array.New(&array, GB_T_INTEGER, 2); *((int *)GB.Array.Get(array, 0)) = r.x(); *((int *)GB.Array.Get(array, 1)) = r.y(); GB.ReturnObject(array); } else if (type == QT_T_QSIZE) { GB_ARRAY array; QSize r; reply >> r; GB.Array.New(&array, GB_T_INTEGER, 2); *((int *)GB.Array.Get(array, 0)) = r.width(); *((int *)GB.Array.Get(array, 1)) = r.height(); GB.ReturnObject(array); } else if (type == QT_T_QRECT) { GB_ARRAY array; QRect r; reply >> r; GB.Array.New(&array, GB_T_INTEGER, 4); *((int *)GB.Array.Get(array, 0)) = r.x(); *((int *)GB.Array.Get(array, 1)) = r.y(); *((int *)GB.Array.Get(array, 2)) = r.width(); *((int *)GB.Array.Get(array, 3)) = r.height(); GB.ReturnObject(array); } else { qWarning("Cannot unmarshall %s", (const char *)ctype); GB.ReturnNull(); } return false; } BEGIN_METHOD(CAPPLICATION_unknown, GB_VALUE param[0]) if (GB.IsProperty()) { if (call_method(THIS, NULL, GB.GetUnknown(), NULL, 0, false)) get_object(THIS, GB.GetUnknown()); } else { call_method(THIS, THIS->object, GB.GetUnknown(), ARG(param[0]), GB.NParam(), true); GB.FreeString(&THIS->object); } END_METHOD #undef THIS #define THIS ((CDCOPREF *)_object) BEGIN_METHOD_VOID(CDCOPREF_free) delete THIS->ref; THIS->ref = 0; //qDebug("Delete DCOPREF %p", _object); END_METHOD BEGIN_METHOD(CDCOPREF_unknown, GB_VALUE param[0]) CAPPLICATION *app; DCOPRef *ref = THIS->ref; //qDebug("Calling DCOPREF %p", _object); app = get_application(ref->app()); call_method(app, ref->object(), GB.GetUnknown(), ARG(param[0]), GB.NParam(), true); END_METHOD BEGIN_PROPERTY(CDCOPREF_name) GB.ReturnNewZeroString(THIS->ref->object()); END_PROPERTY BEGIN_PROPERTY(CDCOPREF_application) GB.ReturnObject(get_application(THIS->ref->app())); END_PROPERTY GB_DESC CKDEObjectDesc[] = { GB_DECLARE(".KDEObject", 0), GB_VIRTUAL_CLASS(), GB_METHOD("_unknown", "v", CAPPLICATION_unknown, "."), GB_END_DECLARE }; GB_DESC CKDEDCOPRefDesc[] = { GB_DECLARE("DCOPRef", sizeof(CDCOPREF)), GB_NOT_CREATABLE(), GB_METHOD("_free", NULL, CDCOPREF_free, NULL), GB_METHOD("_unknown", "v", CDCOPREF_unknown, "."), GB_PROPERTY_READ("Name", "s", CDCOPREF_name), GB_PROPERTY_READ("Application", "KDEApplication", CDCOPREF_application), GB_END_DECLARE }; GB_DESC CKDEApplicationDesc[] = { GB_DECLARE("KDEApplication", sizeof(CAPPLICATION)), GB_NOT_CREATABLE(), GB_STATIC_METHOD("_exit", NULL, CAPPLICATION_exit, NULL), GB_METHOD("_free", NULL, CAPPLICATION_free, NULL), GB_PROPERTY_READ("Name", "s", CAPPLICATION_name), GB_METHOD("_get", ".KDEObject", CAPPLICATION_get_object, "(Object)s"), GB_METHOD("_unknown", "v", CAPPLICATION_unknown, "."), GB_END_DECLARE }; GB_DESC CApplicationDesc[] = { GB_DECLARE("Application", 0), GB_VIRTUAL_CLASS(), GB_STATIC_METHOD("_get", "KDEApplication", CAPPLICATION_get, "(Name)s"), //GB_STATIC_METHOD("_next", "KDEApplication", CAPPLICATION_next, NULL), //GB_STATIC_PROPERTY("Title", "s", CDIALOG_title), GB_END_DECLARE };